Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ group("flutter") {
public_deps += [ "//flutter/testing/scenario_app" ]
}

if (is_android && flutter_runtime_mode == "profile" &&
current_cpu == "arm64") {
public_deps += [ "//flutter/testing/android_background_image" ]
}

# Compile all unittests targets if enabled.
if (enable_unittests) {
public_deps += [
Expand Down
60 changes: 36 additions & 24 deletions ci/firebase_testlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,28 @@


def RunFirebaseTest(apk, results_dir):
try:
# game-loop tests are meant for OpenGL apps.
# This type of test will give the application a handle to a file, and
# we'll write the timeline JSON to that file.
# See https://firebase.google.com/docs/test-lab/android/game-loop
# Pixel 4. As of this commit, this is a highly available device in FTL.
subprocess.check_output([
'gcloud',
'--project', 'flutter-infra',
'firebase', 'test', 'android', 'run',
'--type', 'game-loop',
'--app', apk,
'--timeout', '2m',
'--results-bucket', bucket,
'--results-dir', results_dir,
'--device', 'model=flame,version=29',
])
except subprocess.CalledProcessError as ex:
print(ex.output)
# Recipe will retry return codes from firebase that indicate an infra
# failure.
sys.exit(ex.returncode)
# game-loop tests are meant for OpenGL apps.
# This type of test will give the application a handle to a file, and
# we'll write the timeline JSON to that file.
# See https://firebase.google.com/docs/test-lab/android/game-loop
# Pixel 4. As of this commit, this is a highly available device in FTL.
process = subprocess.Popen(
[
'gcloud',
'--project', 'flutter-infra',
'firebase', 'test', 'android', 'run',
'--type', 'game-loop',
'--app', apk,
'--timeout', '2m',
'--results-bucket', bucket,
'--results-dir', results_dir,
'--device', 'model=flame,version=29',
],
stdout=subprocess.PIPE,
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.



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

results = []
for apk in apks:
results_dir = '%s/%s/%s' % (os.path.basename(apk), git_revision, args.build_id)

RunFirebaseTest(apk, results_dir)
process = RunFirebaseTest(apk, results_dir)
results.append((results_dir, process))

for results_dir, process in results:
for line in iter(process.stdout.readline, ""):
print(line.strip())
return_code = process.wait()
if return_code != 0:
print('Firebase test failed ' + returncode)
sys.exit(process.returncode)

print('Checking logcat for %s' % results_dir)
CheckLogcat(results_dir)
# scenario_app produces a timeline, but the android image test does not.
if 'scenario' in apk:
print('Checking timeline for %s' % results_dir)
CheckTimeline(results_dir)

return 0
Expand Down
3 changes: 3 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,7 @@ FILE: ../../../flutter/shell/common/shell_unittests.cc
FILE: ../../../flutter/shell/common/skia_event_tracer_impl.cc
FILE: ../../../flutter/shell/common/skia_event_tracer_impl.h
FILE: ../../../flutter/shell/common/skp_shader_warmup_unittests.cc
FILE: ../../../flutter/shell/common/snapshot_surface_producer.h
FILE: ../../../flutter/shell/common/switches.cc
FILE: ../../../flutter/shell/common/switches.h
FILE: ../../../flutter/shell/common/thread_host.cc
Expand Down Expand Up @@ -932,6 +933,8 @@ FILE: ../../../flutter/shell/platform/android/surface/android_surface.cc
FILE: ../../../flutter/shell/platform/android/surface/android_surface.h
FILE: ../../../flutter/shell/platform/android/surface/android_surface_mock.cc
FILE: ../../../flutter/shell/platform/android/surface/android_surface_mock.h
FILE: ../../../flutter/shell/platform/android/surface/snapshot_surface_producer.cc
FILE: ../../../flutter/shell/platform/android/surface/snapshot_surface_producer.h
FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.cc
FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.h
FILE: ../../../flutter/shell/platform/common/accessibility_bridge.cc
Expand Down
1 change: 1 addition & 0 deletions shell/common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ source_set("common") {
"shell_io_manager.h",
"skia_event_tracer_impl.cc",
"skia_event_tracer_impl.h",
"snapshot_surface_producer.h",
"switches.cc",
"switches.h",
"thread_host.cc",
Expand Down
6 changes: 5 additions & 1 deletion shell/common/platform_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ void PlatformView::SetViewportMetrics(const ViewportMetrics& metrics) {

void PlatformView::NotifyCreated() {
std::unique_ptr<Surface> surface;

// Threading: We want to use the platform view on the non-platform thread.
// Using the weak pointer is illegal. But, we are going to introduce a latch
// so that the platform view is not collected till the surface is obtained.
Expand Down Expand Up @@ -182,4 +181,9 @@ void PlatformView::UpdateAssetResolverByType(
delegate_.UpdateAssetResolverByType(std::move(updated_asset_resolver), type);
}

std::unique_ptr<SnapshotSurfaceProducer>
PlatformView::CreateSnapshotSurfaceProducer() {
return nullptr;
}

} // namespace flutter
21 changes: 18 additions & 3 deletions shell/common/platform_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class PlatformView {
/// Metal, Vulkan) specific. This is usually a sign to the
/// rasterizer to set up and begin rendering to that surface.
///
/// @param[in] surface The surface
/// @param[in] surface The surface
///
virtual void OnPlatformViewCreated(std::unique_ptr<Surface> surface) = 0;

Expand Down Expand Up @@ -796,6 +796,22 @@ class PlatformView {
std::unique_ptr<AssetResolver> updated_asset_resolver,
AssetResolver::AssetResolverType type);

//--------------------------------------------------------------------------
/// @brief Creates an object that produces surfaces suitable for raster
/// snapshotting. The rasterizer will request this surface if no
/// on screen surface is currently available when an application
/// requests a snapshot, e.g. if `Scene.toImage` or
/// `Picture.toImage` are called while the application is in the
/// background.
///
/// Not all backends support this kind of surface usage, and the
/// default implementation returns nullptr. Platforms should
/// override this if they can support GPU operations in the
/// background and support GPU resource context usage.
///
virtual std::unique_ptr<SnapshotSurfaceProducer>
CreateSnapshotSurfaceProducer();

protected:
PlatformView::Delegate& delegate_;
const TaskRunners task_runners_;
Expand All @@ -804,8 +820,7 @@ class PlatformView {
SkISize size_;
fml::WeakPtrFactory<PlatformView> weak_factory_;

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

private:
Expand Down
36 changes: 27 additions & 9 deletions shell/common/rasterizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -258,11 +258,22 @@ sk_sp<SkImage> Rasterizer::DoMakeRasterSnapshot(
sk_sp<SkImage> result;
SkImageInfo image_info = SkImageInfo::MakeN32Premul(
size.width(), size.height(), SkColorSpace::MakeSRGB());
if (surface_ == nullptr || surface_->GetContext() == nullptr) {

std::unique_ptr<Surface> pbuffer_surface;
Surface* snapshot_surface = nullptr;
if (surface_ && surface_->GetContext()) {
snapshot_surface = surface_.get();
} else if (snapshot_surface_producer_) {
pbuffer_surface = snapshot_surface_producer_->CreateSnapshotSurface();
if (pbuffer_surface && pbuffer_surface->GetContext())
snapshot_surface = pbuffer_surface.get();
}

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

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> surface = SkSurface::MakeRaster(image_info);
result = DrawSnapshot(surface, draw_callback);
sk_sp<SkSurface> sk_surface = SkSurface::MakeRaster(image_info);
result = DrawSnapshot(sk_surface, draw_callback);
} else {
delegate_.GetIsGpuDisabledSyncSwitch()->Execute(
fml::SyncSwitch::Handlers()
Expand All @@ -271,12 +282,14 @@ sk_sp<SkImage> Rasterizer::DoMakeRasterSnapshot(
result = DrawSnapshot(surface, draw_callback);
})
.SetIfFalse([&] {
auto context_switch = surface_->MakeRenderContextCurrent();
FML_DCHECK(snapshot_surface);
auto context_switch =
snapshot_surface->MakeRenderContextCurrent();
if (!context_switch->GetResult()) {
return;
}

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

// When there is an on screen surface, we need a render target
// SkSurface because we want to access texture backed images.
sk_sp<SkSurface> surface =
sk_sp<SkSurface> sk_surface =
SkSurface::MakeRenderTarget(context, // context
SkBudgeted::kNo, // budgeted
image_info // image info
);
if (!surface) {
if (!sk_surface) {
FML_LOG(ERROR)
<< "DoMakeRasterSnapshot can not create GPU render target";
return;
}

surface->getCanvas()->scale(scale_factor, scale_factor);
result = DrawSnapshot(surface, draw_callback);
sk_surface->getCanvas()->scale(scale_factor, scale_factor);
result = DrawSnapshot(sk_surface, draw_callback);
}));
}

Expand Down Expand Up @@ -700,6 +713,11 @@ void Rasterizer::SetExternalViewEmbedder(
external_view_embedder_ = view_embedder;
}

void Rasterizer::SetSnapshotSurfaceProducer(
std::unique_ptr<SnapshotSurfaceProducer> producer) {
snapshot_surface_producer_ = std::move(producer);
}

void Rasterizer::FireNextFrameCallbackIfPresent() {
if (!next_frame_callback_) {
return;
Expand Down
15 changes: 14 additions & 1 deletion shell/common/rasterizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "flutter/fml/time/time_point.h"
#include "flutter/lib/ui/snapshot_delegate.h"
#include "flutter/shell/common/pipeline.h"
#include "flutter/shell/common/snapshot_surface_producer.h"

namespace flutter {

Expand Down Expand Up @@ -98,7 +99,7 @@ class Rasterizer final : public SnapshotDelegate {
/// currently only created by the shell (which also sets itself up
/// as the rasterizer delegate).
///
/// @param[in] delegate The rasterizer delegate.
/// @param[in] delegate The rasterizer delegate.
///
Rasterizer(Delegate& delegate);

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

//----------------------------------------------------------------------------
/// @brief Set the snapshot surface producer. This is done on shell
/// initialization. This is non-null on platforms that support taking
/// GPU accelerated raster snapshots in the background.
///
/// @param[in] producer A surface producer for raster snapshotting when the
/// onscreen surface is not available.
///
void SetSnapshotSurfaceProducer(
std::unique_ptr<SnapshotSurfaceProducer> producer);

//----------------------------------------------------------------------------
/// @brief Returns a pointer to the compositor context used by this
/// rasterizer. This pointer will never be `nullptr`.
Expand Down Expand Up @@ -434,6 +446,7 @@ class Rasterizer final : public SnapshotDelegate {
private:
Delegate& delegate_;
std::unique_ptr<Surface> surface_;
std::unique_ptr<SnapshotSurfaceProducer> snapshot_surface_producer_;
std::unique_ptr<flutter::CompositorContext> compositor_context_;
// This is the last successfully rasterized layer tree.
std::unique_ptr<flutter::LayerTree> last_layer_tree_;
Expand Down
1 change: 1 addition & 0 deletions shell/common/rasterizer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class MockDelegate : public Rasterizer::Delegate {
MOCK_CONST_METHOD0(GetTaskRunners, const TaskRunners&());
MOCK_CONST_METHOD0(GetIsGpuDisabledSyncSwitch,
std::shared_ptr<const fml::SyncSwitch>());
MOCK_METHOD0(CreateSnapshotSurface, std::unique_ptr<Surface>());
};

class MockSurface : public Surface {
Expand Down
2 changes: 2 additions & 0 deletions shell/common/shell.cc
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,8 @@ bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
// Set the external view embedder for the rasterizer.
auto view_embedder = platform_view_->CreateExternalViewEmbedder();
rasterizer_->SetExternalViewEmbedder(view_embedder);
rasterizer_->SetSnapshotSurfaceProducer(
platform_view_->CreateSnapshotSurfaceProducer());

// The weak ptr must be generated in the platform thread which owns the unique
// ptr.
Expand Down
22 changes: 22 additions & 0 deletions shell/common/snapshot_surface_producer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SHELL_COMMON_SNAPSHOT_SURFACE_PRODUCER_H_
#define SHELL_COMMON_SNAPSHOT_SURFACE_PRODUCER_H_

#include <memory>

#include "flutter/flow/surface.h"

namespace flutter {

class SnapshotSurfaceProducer {
public:
virtual ~SnapshotSurfaceProducer() = default;

virtual std::unique_ptr<Surface> CreateSnapshotSurface() = 0;
};

} // namespace flutter
#endif // SHELL_COMMON_SNAPSHOT_SURFACE_PRODUCER_H_
10 changes: 10 additions & 0 deletions shell/platform/android/android_context_gl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,16 @@ std::unique_ptr<AndroidEGLSurface> AndroidContextGL::CreateOffscreenSurface()
resource_context_);
}

std::unique_ptr<AndroidEGLSurface> AndroidContextGL::CreatePbufferSurface()
const {
EGLDisplay display = environment_->Display();

const EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};

EGLSurface surface = eglCreatePbufferSurface(display, config_, attribs);
return std::make_unique<AndroidEGLSurface>(surface, display, context_);
}

fml::RefPtr<AndroidEnvironmentGL> AndroidContextGL::Environment() const {
return environment_;
}
Expand Down
8 changes: 8 additions & 0 deletions shell/platform/android/android_context_gl.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ class AndroidContextGL : public AndroidContext {
///
std::unique_ptr<AndroidEGLSurface> CreateOffscreenSurface() const;

//----------------------------------------------------------------------------
/// @brief Allocates an 1x1 pbuffer surface that is used for making the
/// onscreen context current for snapshotting.
///
/// @return The pbuffer surface.
///
std::unique_ptr<AndroidEGLSurface> CreatePbufferSurface() const;

//----------------------------------------------------------------------------
/// @return The Android environment that contains a reference to the
/// display.
Expand Down
12 changes: 12 additions & 0 deletions shell/platform/android/android_surface_gl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,16 @@ AndroidContextGL* AndroidSurfaceGL::GLContextPtr() const {
return reinterpret_cast<AndroidContextGL*>(android_context_.get());
}

std::unique_ptr<Surface> AndroidSurfaceGL::CreatePbufferSurface() {
onscreen_surface_ = GLContextPtr()->CreatePbufferSurface();
sk_sp<GrDirectContext> main_skia_context =
GLContextPtr()->GetMainSkiaContext();
if (!main_skia_context) {
main_skia_context = GPUSurfaceGL::MakeGLContext(this);
GLContextPtr()->SetMainSkiaContext(main_skia_context);
}

return std::make_unique<GPUSurfaceGL>(main_skia_context, this, true);
}

} // namespace flutter
3 changes: 3 additions & 0 deletions shell/platform/android/android_surface_gl.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class AndroidSurfaceGL final : public GPUSurfaceGLDelegate,
// |AndroidSurface|
bool SetNativeWindow(fml::RefPtr<AndroidNativeWindow> window) override;

// |AndroidSurface|
virtual std::unique_ptr<Surface> CreatePbufferSurface() override;

// |GPUSurfaceGLDelegate|
std::unique_ptr<GLContextResult> GLContextMakeCurrent() override;

Expand Down
Loading