Flutter Engine
image_dispose_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #define FML_USED_ON_EMBEDDER
6 
7 #include "flutter/common/task_runners.h"
8 #include "flutter/fml/synchronization/waitable_event.h"
9 #include "flutter/lib/ui/painting/image.h"
10 #include "flutter/lib/ui/painting/picture.h"
11 #include "flutter/runtime/dart_vm.h"
12 #include "flutter/shell/common/shell_test.h"
13 #include "flutter/shell/common/thread_host.h"
14 #include "flutter/testing/testing.h"
15 
16 namespace flutter {
17 namespace testing {
18 
19 class ImageDisposeTest : public ShellTest {
20  public:
21  template <class T>
22  T* GetNativePeer(Dart_Handle handle) {
23  intptr_t peer = 0;
24  auto native_handle = Dart_GetNativeInstanceField(
25  handle, tonic::DartWrappable::kPeerIndex, &peer);
26  EXPECT_FALSE(Dart_IsError(native_handle)) << Dart_GetError(native_handle);
27  return reinterpret_cast<T*>(peer);
28  }
29 
30  // Used to wait on Dart callbacks or Shell task runner flushing
32 
34  static void picture_finalizer(void* isolate_callback_data, void* peer) {
35  auto latch = reinterpret_cast<fml::AutoResetWaitableEvent*>(peer);
36  latch->Signal();
37  }
38 
39  sk_sp<SkPicture> current_picture_;
40  sk_sp<SkImage> current_image_;
41 };
42 
43 TEST_F(ImageDisposeTest, ImageReleasedAfterFrame) {
44  auto native_capture_image_and_picture = [&](Dart_NativeArguments args) {
45  auto image_handle = Dart_GetNativeArgument(args, 0);
46  auto native_image_handle =
47  Dart_GetField(image_handle, Dart_NewStringFromCString("_image"));
48  ASSERT_FALSE(Dart_IsError(native_image_handle))
49  << Dart_GetError(native_image_handle);
50  ASSERT_FALSE(Dart_IsNull(native_image_handle));
51  CanvasImage* image = GetNativePeer<CanvasImage>(native_image_handle);
52  Picture* picture = GetNativePeer<Picture>(Dart_GetNativeArgument(args, 1));
53  ASSERT_FALSE(image->image()->unique());
54  ASSERT_FALSE(picture->picture()->unique());
55  current_image_ = image->image();
56  current_picture_ = picture->picture();
57 
58  Dart_NewFinalizableHandle(Dart_GetNativeArgument(args, 1),
60  };
61 
62  auto native_on_begin_frame_done = [&](Dart_NativeArguments args) {
64  };
65 
67  auto task_runner = CreateNewThread();
68  TaskRunners task_runners("test", // label
69  GetCurrentTaskRunner(), // platform
70  task_runner, // raster
71  task_runner, // ui
72  task_runner // io
73  );
74 
75  AddNativeCallback("CaptureImageAndPicture",
76  CREATE_NATIVE_ENTRY(native_capture_image_and_picture));
77  AddNativeCallback("OnBeginFrameDone",
78  CREATE_NATIVE_ENTRY(native_on_begin_frame_done));
79 
80  std::unique_ptr<Shell> shell = CreateShell(std::move(settings), task_runners);
81 
82  ASSERT_TRUE(shell->IsSetup());
83 
84  SetViewportMetrics(shell.get(), 800, 600);
85 
86  shell->GetPlatformView()->NotifyCreated();
87 
88  auto configuration = RunConfiguration::InferFromSettings(settings);
89  configuration.SetEntrypoint("pumpImage");
90 
91  shell->RunEngine(std::move(configuration), [&](auto result) {
92  ASSERT_EQ(result, Engine::RunStatus::Success);
93  });
94 
96 
97  ASSERT_TRUE(current_picture_);
98  ASSERT_TRUE(current_image_);
99 
100  // Simulate a large notify idle, as the animator would do
101  // when it has no frames left.
102  // On slower machines, this is especially important - we capture that
103  // this happens normally in devicelab bnechmarks like large_image_changer.
104  NotifyIdle(shell.get(), Dart_TimelineGetMicros() + 100000);
105 
107 
108  // Force a drain the SkiaUnrefQueue.
110  task_runner->PostTask([&, io_manager = shell->GetIOManager()]() {
111  io_manager->GetSkiaUnrefQueue()->Drain();
113  });
115 
116  EXPECT_TRUE(current_picture_->unique());
117  current_picture_.reset();
118 
119  EXPECT_TRUE(current_image_->unique());
120  current_image_.reset();
121 
122  shell->GetPlatformView()->NotifyDestroyed();
123  DestroyShell(std::move(shell), std::move(task_runners));
124 }
125 
126 } // namespace testing
127 } // namespace flutter
G_BEGIN_DECLS FlValue * args
fml::RefPtr< fml::TaskRunner > GetCurrentTaskRunner()
Get the task runner for the thread that the current unit-test is running on. This creates a message l...
Definition: thread_test.cc:22
fml::AutoResetWaitableEvent picture_finalizer_latch_
fml::RefPtr< fml::TaskRunner > CreateNewThread(std::string name="")
Creates a new thread, initializes a message loop on it, and, returns its task runner to the unit-test...
Definition: thread_test.cc:26
static void picture_finalizer(void *isolate_callback_data, void *peer)
static void SetViewportMetrics(Shell *shell, double width, double height)
Definition: shell_test.cc:110
static RunConfiguration InferFromSettings(const Settings &settings, fml::RefPtr< fml::TaskRunner > io_worker=nullptr)
Attempts to infer a run configuration from the settings object. This tries to create a run configurat...
void DestroyShell(std::unique_ptr< Shell > shell)
Definition: shell_test.cc:340
static void NotifyIdle(Shell *shell, int64_t deadline)
Definition: shell_test.cc:146
#define CREATE_NATIVE_ENTRY(native_entry)
Settings CreateSettingsForFixture() override
Definition: shell_test.cc:273
TEST_F(BackdropFilterLayerTest, PaintingEmptyLayerDies)
fml::AutoResetWaitableEvent message_latch_
void AddNativeCallback(std::string name, Dart_NativeFunction callback)
Definition: fixture_test.cc:58
sk_sp< SkImage > image() const
Definition: image.h:37
std::unique_ptr< Shell > CreateShell(Settings settings, bool simulate_vsync=false)
Definition: shell_test.cc:306