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

Commit 233d4b7

Browse files
committed
Use a pbuffer on Andorid when in the background
1 parent 2eab395 commit 233d4b7

19 files changed

+150
-21
lines changed

shell/common/platform_view.cc

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,26 +67,32 @@ void PlatformView::SetViewportMetrics(const ViewportMetrics& metrics) {
6767

6868
void PlatformView::NotifyCreated() {
6969
std::unique_ptr<Surface> surface;
70-
70+
std::unique_ptr<Surface> snapshot_surface;
7171
// Threading: We want to use the platform view on the non-platform thread.
7272
// Using the weak pointer is illegal. But, we are going to introduce a latch
7373
// so that the platform view is not collected till the surface is obtained.
7474
auto* platform_view = this;
7575
fml::ManualResetWaitableEvent latch;
7676
fml::TaskRunner::RunNowOrPostTask(
77-
task_runners_.GetRasterTaskRunner(), [platform_view, &surface, &latch]() {
77+
task_runners_.GetRasterTaskRunner(),
78+
[platform_view, &surface, &latch, &snapshot_surface]() {
7879
surface = platform_view->CreateRenderingSurface();
7980
if (surface && !surface->IsValid()) {
8081
surface.reset();
8182
}
83+
snapshot_surface = platform_view->CreateRasterSnapshotSurface();
84+
if (snapshot_surface && !snapshot_surface->IsValid()) {
85+
snapshot_surface.reset();
86+
}
8287
latch.Signal();
8388
});
8489
latch.Wait();
8590
if (!surface) {
8691
FML_LOG(ERROR) << "Failed to create platform view rendering surface";
8792
return;
8893
}
89-
delegate_.OnPlatformViewCreated(std::move(surface));
94+
delegate_.OnPlatformViewCreated(std::move(surface),
95+
std::move(snapshot_surface));
9096
}
9197

9298
void PlatformView::NotifyDestroyed() {
@@ -182,4 +188,8 @@ void PlatformView::UpdateAssetResolverByType(
182188
delegate_.UpdateAssetResolverByType(std::move(updated_asset_resolver), type);
183189
}
184190

191+
std::unique_ptr<Surface> PlatformView::CreateRasterSnapshotSurface() {
192+
return nullptr;
193+
}
194+
185195
} // namespace flutter

shell/common/platform_view.h

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,16 @@ 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
66+
/// @param[in] snapshot_surface A surface suitable taking raster snapshots
67+
/// if surface has been collected. This
68+
/// parameter may be null if backgorund
69+
/// snapshotting is not supported by the
70+
/// platform.
6671
///
67-
virtual void OnPlatformViewCreated(std::unique_ptr<Surface> surface) = 0;
72+
virtual void OnPlatformViewCreated(
73+
std::unique_ptr<Surface> surface,
74+
std::unique_ptr<Surface> snapshot_surface) = 0;
6875

6976
//--------------------------------------------------------------------------
7077
/// @brief Notifies the delegate that the platform view was destroyed.
@@ -804,7 +811,23 @@ class PlatformView {
804811
SkISize size_;
805812
fml::WeakPtrFactory<PlatformView> weak_factory_;
806813

807-
// Unlike all other methods on the platform view, this is called on the
814+
//--------------------------------------------------------------------------
815+
/// @brief Creates a Surface suitable for raster snapshotting. The
816+
/// rasterizer will request this surface if no on screen surface
817+
/// is currently available and a snapshot has been requested
818+
/// by the framework, e.g. if `Scene.toImage` or `Picture.toImage`
819+
/// are called while the application is in the background.
820+
///
821+
/// Not all backends support this kind of surface usage, and the
822+
/// default implementation returns nullptr. Platforms should
823+
/// override this if they can support GPU operations in the
824+
/// background and support GPU resource context usage.
825+
///
826+
/// This is the only public method of this interface called on the
827+
/// raster task runner.
828+
virtual std::unique_ptr<Surface> CreateRasterSnapshotSurface();
829+
830+
// This and CreateRasterSnapshotSurface are the only methods called on the
808831
// raster task runner.
809832
virtual std::unique_ptr<Surface> CreateRenderingSurface();
810833

shell/common/rasterizer.cc

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -258,11 +258,19 @@ 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::shared_ptr<Surface> pbuffer_surface;
263+
if (!surface_) {
264+
pbuffer_surface = delegate_.GetSnapshotSurface();
265+
}
266+
267+
if ((surface_ == nullptr || surface_->GetContext() == nullptr) &&
268+
(pbuffer_surface == nullptr ||
269+
pbuffer_surface->GetContext() == nullptr)) {
262270
// Raster surface is fine if there is no on screen surface. This might
263271
// happen in case of software rendering.
264-
sk_sp<SkSurface> surface = SkSurface::MakeRaster(image_info);
265-
result = DrawSnapshot(surface, draw_callback);
272+
sk_sp<SkSurface> sk_surface = SkSurface::MakeRaster(image_info);
273+
result = DrawSnapshot(sk_surface, draw_callback);
266274
} else {
267275
delegate_.GetIsGpuDisabledSyncSwitch()->Execute(
268276
fml::SyncSwitch::Handlers()
@@ -271,12 +279,17 @@ sk_sp<SkImage> Rasterizer::DoMakeRasterSnapshot(
271279
result = DrawSnapshot(surface, draw_callback);
272280
})
273281
.SetIfFalse([&] {
274-
auto context_switch = surface_->MakeRenderContextCurrent();
282+
Surface* surface = surface_.get();
283+
if (!surface) {
284+
surface = pbuffer_surface.get();
285+
}
286+
FML_DCHECK(surface);
287+
auto context_switch = surface->MakeRenderContextCurrent();
275288
if (!context_switch->GetResult()) {
276289
return;
277290
}
278291

279-
GrRecordingContext* context = surface_->GetContext();
292+
GrRecordingContext* context = 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

@@ -680,6 +693,7 @@ Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree(
680693
FML_LOG(ERROR) << "Screenshot data was null.";
681694
return {};
682695
}
696+
FML_DLOG(ERROR) << data;
683697

684698
if (base64_encode) {
685699
size_t b64_size = SkBase64::Encode(data->data(), data->size(), nullptr);

shell/common/rasterizer.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@ class Rasterizer final : public SnapshotDelegate {
9090
/// is critical that GPU operations are not processed.
9191
virtual std::shared_ptr<const fml::SyncSwitch> GetIsGpuDisabledSyncSwitch()
9292
const = 0;
93+
94+
/// Called by the Rasterizer if a snapshot is requested while no surface
95+
/// is currently available, for example after a platform has torn down
96+
/// the surface.
97+
///
98+
/// For some rendering backends or some platforms, using a GPU surface for
99+
/// snapshotting while in the background may not be possible or necessary.
100+
/// In that case, this method must return nullptr and the rasterizer will
101+
/// attempt to use a CPU based raster surface for snapshotting.
102+
virtual std::shared_ptr<Surface> GetSnapshotSurface() = 0;
93103
};
94104

95105
//----------------------------------------------------------------------------

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(CreateRasterSnapshotSurface, std::unique_ptr<Surface>());
3334
};
3435

3536
class MockSurface : public Surface {

shell/common/shell.cc

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,11 +697,14 @@ DartVM* Shell::GetDartVM() {
697697
}
698698

699699
// |PlatformView::Delegate|
700-
void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface) {
700+
void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface,
701+
std::unique_ptr<Surface> snapshot_surface) {
701702
TRACE_EVENT0("flutter", "Shell::OnPlatformViewCreated");
702703
FML_DCHECK(is_setup_);
703704
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
704705

706+
snapshot_surface_ = std::move(snapshot_surface);
707+
705708
// Prevent any request to change the thread configuration for raster and
706709
// platform queues while the platform view is being created.
707710
//
@@ -1362,6 +1365,12 @@ void Shell::ReportTimings() {
13621365
});
13631366
}
13641367

1368+
std::shared_ptr<Surface> Shell::GetSnapshotSurface() {
1369+
FML_DCHECK(is_setup_);
1370+
FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread());
1371+
return snapshot_surface_;
1372+
}
1373+
13651374
size_t Shell::UnreportedFramesCount() const {
13661375
// Check that this is running on the raster thread to avoid race conditions.
13671376
FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread());

shell/common/shell.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,10 @@ class Shell final : public PlatformView::Delegate,
435435

436436
sk_sp<GrDirectContext> shared_resource_context_;
437437

438+
// Created by the PlatformView on the raster task runner, used by the
439+
// Rasterizer if the onscreen surface is unavailable.
440+
std::shared_ptr<Surface> snapshot_surface_;
441+
438442
Shell(DartVMRef vm,
439443
TaskRunners task_runners,
440444
Settings settings,
@@ -470,7 +474,9 @@ class Shell final : public PlatformView::Delegate,
470474
void ReportTimings();
471475

472476
// |PlatformView::Delegate|
473-
void OnPlatformViewCreated(std::unique_ptr<Surface> surface) override;
477+
void OnPlatformViewCreated(
478+
std::unique_ptr<Surface> surface,
479+
std::unique_ptr<Surface> snapshot_surface) override;
474480

475481
// |PlatformView::Delegate|
476482
void OnPlatformViewDestroyed() override;
@@ -590,6 +596,9 @@ class Shell final : public PlatformView::Delegate,
590596
// |Rasterizer::Delegate|
591597
fml::TimePoint GetLatestFrameTargetTime() const override;
592598

599+
// |Rasterizer::Delegate|
600+
std::shared_ptr<Surface> GetSnapshotSurface() override;
601+
593602
// |ServiceProtocol::Handler|
594603
fml::RefPtr<fml::TaskRunner> GetServiceProtocolHandlerTaskRunner(
595604
std::string_view method) const override;

shell/platform/android/android_context_gl.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,16 @@ std::unique_ptr<AndroidEGLSurface> AndroidContextGL::CreateOffscreenSurface()
227227
resource_context_);
228228
}
229229

230+
std::unique_ptr<AndroidEGLSurface> AndroidContextGL::CreatePbufferSurface()
231+
const {
232+
EGLDisplay display = environment_->Display();
233+
234+
const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
235+
236+
EGLSurface surface = eglCreatePbufferSurface(display, config_, attribs);
237+
return std::make_unique<AndroidEGLSurface>(surface, display, context_);
238+
}
239+
230240
fml::RefPtr<AndroidEnvironmentGL> AndroidContextGL::Environment() const {
231241
return environment_;
232242
}

shell/platform/android/android_context_gl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ class AndroidContextGL : public AndroidContext {
9393
///
9494
std::unique_ptr<AndroidEGLSurface> CreateOffscreenSurface() const;
9595

96+
//----------------------------------------------------------------------------
97+
/// @brief Allocates an 1x1 pbuffer surface that is used for making the
98+
/// onscreen context current for snapshotting.
99+
///
100+
/// @return The pbuffer surface.
101+
///
102+
std::unique_ptr<AndroidEGLSurface> CreatePbufferSurface() const;
103+
96104
//----------------------------------------------------------------------------
97105
/// @return The Android environment that contains a reference to the
98106
/// display.

shell/platform/android/android_surface_gl.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,4 +175,16 @@ AndroidContextGL* AndroidSurfaceGL::GLContextPtr() const {
175175
return reinterpret_cast<AndroidContextGL*>(android_context_.get());
176176
}
177177

178+
std::unique_ptr<Surface> AndroidSurfaceGL::CreatePbufferSurface() {
179+
onscreen_surface_ = GLContextPtr()->CreatePbufferSurface();
180+
sk_sp<GrDirectContext> main_skia_context =
181+
GLContextPtr()->GetMainSkiaContext();
182+
if (!main_skia_context) {
183+
main_skia_context = GPUSurfaceGL::MakeGLContext(this);
184+
GLContextPtr()->SetMainSkiaContext(main_skia_context);
185+
}
186+
187+
return std::make_unique<GPUSurfaceGL>(main_skia_context, this, true);
188+
}
189+
178190
} // namespace flutter

0 commit comments

Comments
 (0)