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 1 commit
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
Prev Previous commit
Next Next commit
test that is hopefully not flaky!
  • Loading branch information
dnfield committed Aug 26, 2020
commit eee1b3308914e16183fad4d2594ea8b72776fd2b
1 change: 1 addition & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ FILE: ../../../flutter/lib/ui/painting/image_decoder.h
FILE: ../../../flutter/lib/ui/painting/image_decoder_unittests.cc
FILE: ../../../flutter/lib/ui/painting/image_descriptor.cc
FILE: ../../../flutter/lib/ui/painting/image_descriptor.h
FILE: ../../../flutter/lib/ui/painting/image_dispose_unittests.cc
FILE: ../../../flutter/lib/ui/painting/image_encoding.cc
FILE: ../../../flutter/lib/ui/painting/image_encoding.h
FILE: ../../../flutter/lib/ui/painting/image_encoding_unittests.cc
Expand Down
1 change: 1 addition & 0 deletions lib/ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ if (enable_unittests) {
public_configs = [ "//flutter:export_dynamic_symbols" ]

sources = [
"painting/image_dispose_unittests.cc",
"painting/image_encoding_unittests.cc",
"painting/vertices_unittests.cc",
"window/platform_configuration_unittests.cc",
Expand Down
59 changes: 59 additions & 0 deletions lib/ui/fixtures/ui_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';
import 'dart:typed_data';
import 'dart:ui';

Expand Down Expand Up @@ -73,3 +74,61 @@ Future<void> encodeImageProducesExternalUint8List() async {
void _encodeImage(Image i, int format, void Function(Uint8List result))
native 'EncodeImage';
void _validateExternal(Uint8List result) native 'ValidateExternal';

@pragma('vm:entry-point')
Future<void> pumpImage() async {
const int width = 8000;
const int height = 8000;
final Completer<Image> completer = Completer<Image>();
decodeImageFromPixels(
Uint8List.fromList(List<int>.filled(width * height * 4, 0xFF)),
width,
height,
PixelFormat.rgba8888,
(Image image) => completer.complete(image),
);
final Image image = await completer.future;

final FrameCallback renderBlank = (Duration duration) {
image.dispose();

final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
canvas.drawRect(Rect.largest, Paint());
final Picture picture = recorder.endRecording();

final SceneBuilder builder = SceneBuilder();
builder.addPicture(Offset.zero, picture);

final Scene scene = builder.build();
window.render(scene);
scene.dispose();
window.onBeginFrame = (Duration duration) {
window.onDrawFrame = _onBeginFrameDone;
};
window.scheduleFrame();
};

final FrameCallback renderImage = (Duration duration) {
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
canvas.drawImage(image, Offset.zero, Paint());
final Picture picture = recorder.endRecording();

final SceneBuilder builder = SceneBuilder();
builder.addPicture(Offset.zero, picture);

_captureImageAndPicture(image, picture);

final Scene scene = builder.build();
window.render(scene);
scene.dispose();
window.onBeginFrame = renderBlank;
window.scheduleFrame();
};

window.onBeginFrame = renderImage;
window.scheduleFrame();
}
void _captureImageAndPicture(Image image, Picture picture) native 'CaptureImageAndPicture';
Future<void> _onBeginFrameDone() native 'OnBeginFrameDone';
97 changes: 97 additions & 0 deletions lib/ui/painting/image_dispose_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

Copy link
Member

Choose a reason for hiding this comment

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

stray newline

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

mac flaked out for reasons not related to this test (Xcode install was bad for some reason and then goma failed). Hopefully this gets a clean run for it.

// 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.

#define FML_USED_ON_EMBEDDER

#include "flutter/common/task_runners.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/lib/ui/painting/image.h"
#include "flutter/lib/ui/painting/picture.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/shell/common/shell_test.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/testing/testing.h"

namespace flutter {
namespace testing {

class ImageDisposeTest : public ShellTest {
public:
template <class T>
T* GetNativePeer(Dart_NativeArguments args, int index) {
auto handle = Dart_GetNativeArgument(args, index);
intptr_t peer = 0;
EXPECT_FALSE(Dart_IsError(Dart_GetNativeInstanceField(
handle, tonic::DartWrappable::kPeerIndex, &peer)));
return reinterpret_cast<T*>(peer);
}

// Used to wait on Dart callbacks or Shell task runner flushing
fml::AutoResetWaitableEvent message_latch_;

sk_sp<SkPicture> current_picture_;
sk_sp<SkImage> current_image_;
};

TEST_F(ImageDisposeTest, ImageReleasedAfterFrame) {
auto native_capture_image_and_picture = [&](Dart_NativeArguments args) {
CanvasImage* image = GetNativePeer<CanvasImage>(args, 0);
Picture* picture = GetNativePeer<Picture>(args, 1);
ASSERT_FALSE(image->image()->unique());
ASSERT_FALSE(picture->picture()->unique());
current_image_ = image->image();
current_picture_ = picture->picture();
};

auto native_on_begin_frame_done = [&](Dart_NativeArguments args) {
message_latch_.Signal();
};

Settings settings = CreateSettingsForFixture();
auto task_runner = CreateNewThread();
TaskRunners task_runners("test", // label
GetCurrentTaskRunner(), // platform
task_runner, // raster
task_runner, // ui
task_runner // io
);

AddNativeCallback("CaptureImageAndPicture",
CREATE_NATIVE_ENTRY(native_capture_image_and_picture));
AddNativeCallback("OnBeginFrameDone",
CREATE_NATIVE_ENTRY(native_on_begin_frame_done));

std::unique_ptr<Shell> shell = CreateShell(std::move(settings), task_runners);

ASSERT_TRUE(shell->IsSetup());

SetViewportMetrics(shell.get(), 800, 600);

shell->GetPlatformView()->NotifyCreated();

auto configuration = RunConfiguration::InferFromSettings(settings);
configuration.SetEntrypoint("pumpImage");

shell->RunEngine(std::move(configuration), [&](auto result) {
ASSERT_EQ(result, Engine::RunStatus::Success);
});

message_latch_.Wait();

ASSERT_TRUE(current_picture_);
ASSERT_TRUE(current_image_);

EXPECT_TRUE(current_picture_->unique());
current_picture_.reset();

EXPECT_TRUE(current_image_->unique());
current_image_.reset();

shell->GetPlatformView()->NotifyDestroyed();
DestroyShell(std::move(shell), std::move(task_runners));
}

} // namespace testing
} // namespace flutter
34 changes: 34 additions & 0 deletions shell/common/shell_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,40 @@ void ShellTest::VSyncFlush(Shell* shell, bool& will_draw_new_frame) {
latch.Wait();
}

void ShellTest::SetViewportMetrics(Shell* shell, double width, double height) {
flutter::ViewportMetrics viewport_metrics = {
1, // device pixel ratio
width, // physical width
height, // physical height
0, // padding top
0, // padding right
0, // padding bottom
0, // padding left
0, // view inset top
0, // view inset right
0, // view inset bottom
0, // view inset left
0, // gesture inset top
0, // gesture inset right
0, // gesture inset bottom
0 // gesture inset left
};
// Set viewport to nonempty, and call Animator::BeginFrame to make the layer
// tree pipeline nonempty. Without either of this, the layer tree below
// won't be rasterized.
fml::AutoResetWaitableEvent latch;
shell->GetTaskRunners().GetUITaskRunner()->PostTask(
[&latch, engine = shell->weak_engine_, viewport_metrics]() {
engine->SetViewportMetrics(std::move(viewport_metrics));
const auto frame_begin_time = fml::TimePoint::Now();
const auto frame_end_time =
frame_begin_time + fml::TimeDelta::FromSecondsF(1.0 / 60.0);
engine->animator_->BeginFrame(frame_begin_time, frame_end_time);
latch.Signal();
});
latch.Wait();
}

void ShellTest::PumpOneFrame(Shell* shell,
double width,
double height,
Expand Down
2 changes: 2 additions & 0 deletions shell/common/shell_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ class ShellTest : public FixtureTest {
/// in PumpOneFrame.
using LayerTreeBuilder =
std::function<void(std::shared_ptr<ContainerLayer> root)>;

static void SetViewportMetrics(Shell* shell, double width, double height);
static void PumpOneFrame(Shell* shell,
double width = 1,
double height = 1,
Expand Down