5#include "flutter/lib/ui/painting/image_encoding.h"
6#include "flutter/lib/ui/painting/image_encoding_impl.h"
8#include "flutter/common/task_runners.h"
9#include "flutter/fml/synchronization/waitable_event.h"
10#include "flutter/lib/ui/painting/image.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#include "gmock/gmock.h"
16#include "gtest/gtest.h"
18#if IMPELLER_SUPPORTS_RENDERING
19#include "flutter/lib/ui/painting/image_encoding_impeller.h"
26#pragma GCC diagnostic ignored "-Wunreachable-code"
34class MockDlImage :
public DlImage {
37 MOCK_METHOD(std::shared_ptr<impeller::Texture>,
41 MOCK_METHOD(
bool, isOpaque, (), (
const,
override));
42 MOCK_METHOD(
bool, isTextureBacked, (), (
const,
override));
43 MOCK_METHOD(
bool, isUIThreadSafe, (), (
const,
override));
44 MOCK_METHOD(
SkISize, dimensions, (), (
const,
override));
45 MOCK_METHOD(
size_t, GetApproximateByteSize, (), (
const,
override));
102 Settings settings = CreateSettingsForFixture();
104 GetCurrentTaskRunner(),
111 AddNativeCallback(
"ValidateExternal",
114 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
116 ASSERT_TRUE(shell->IsSetup());
118 configuration.SetEntrypoint(
"encodeImageProducesExternalUint8List");
120 shell->RunEngine(std::move(configuration), [&](
auto result) {
124 message_latch.
Wait();
125 DestroyShell(std::move(shell), task_runners);
129 Settings settings = CreateSettingsForFixture();
131 GetCurrentTaskRunner(),
159 auto is_gpu_disabled_sync_switch =
160 std::make_shared<const MockSyncSwitch>();
161 EXPECT_CALL(*is_gpu_disabled_sync_switch, Execute)
166 io_manager->GetResourceContext(),
167 is_gpu_disabled_sync_switch);
178 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
180 ASSERT_TRUE(shell->IsSetup());
182 configuration.SetEntrypoint(
"encodeImageProducesExternalUint8List");
184 shell->RunEngine(std::move(configuration), [&](
auto result) {
188 message_latch.
Wait();
189 DestroyShell(std::move(shell), task_runners);
192#if IMPELLER_SUPPORTS_RENDERING
193using ::impeller::testing::MockAllocator;
194using ::impeller::testing::MockBlitPass;
195using ::impeller::testing::MockCommandBuffer;
196using ::impeller::testing::MockCommandQueue;
197using ::impeller::testing::MockDeviceBuffer;
198using ::impeller::testing::MockImpellerContext;
199using ::impeller::testing::MockTexture;
201using ::testing::DoAll;
202using ::testing::Invoke;
203using ::testing::InvokeArgument;
204using ::testing::Return;
207std::shared_ptr<impeller::Context> MakeConvertDlImageToSkImageContext(
208 std::vector<uint8_t>&
buffer) {
209 auto context = std::make_shared<MockImpellerContext>();
210 auto command_buffer = std::make_shared<MockCommandBuffer>(context);
211 auto allocator = std::make_shared<MockAllocator>();
212 auto blit_pass = std::make_shared<MockBlitPass>();
213 auto command_queue = std::make_shared<MockCommandQueue>();
216 auto device_buffer = std::make_shared<MockDeviceBuffer>(device_buffer_desc);
217 EXPECT_CALL(*allocator, OnCreateBuffer).WillOnce(Return(device_buffer));
218 EXPECT_CALL(*blit_pass, IsValid).WillRepeatedly(Return(
true));
219 EXPECT_CALL(*command_buffer, IsValid).WillRepeatedly(Return(
true));
220 EXPECT_CALL(*command_buffer, OnCreateBlitPass).WillOnce(Return(blit_pass));
221 EXPECT_CALL(*context, GetResourceAllocator).WillRepeatedly(Return(allocator));
222 EXPECT_CALL(*context, CreateCommandBuffer).WillOnce(Return(command_buffer));
223 EXPECT_CALL(*device_buffer, OnGetContents).WillOnce(Return(
buffer.data()));
224 EXPECT_CALL(*command_queue, Submit(_, _))
228 EXPECT_CALL(*context, GetCommandQueue).WillRepeatedly(Return(command_queue));
233TEST_F(ShellTest, EncodeImageRetries) {
238 Settings
settings = CreateSettingsForFixture();
240 TaskRunners task_runners(
"test",
247 std::unique_ptr<Shell>
shell = CreateShell({
249 .task_runners = task_runners,
257 TurnOffGPU(
shell.get(), value);
270 ASSERT_TRUE(
shell->IsSetup());
272 configuration.SetEntrypoint(
"toByteDataRetries");
274 shell->RunEngine(std::move(configuration), [&](
auto result) {
278 message_latch.
Wait();
279 DestroyShell(std::move(shell), task_runners);
282TEST_F(ShellTest, EncodeImageFailsWithoutGPUImpeller) {
287 Settings
settings = CreateSettingsForFixture();
289 TaskRunners task_runners(
"test",
304 AddNativeCallback(
"ValidateError",
307 std::unique_ptr<Shell>
shell = CreateShell({
309 .task_runners = task_runners,
317 TurnOffGPU(
shell.get(),
true);
323 task_runners.GetIOTaskRunner()->PostTask([&] {
324 std::shared_ptr<impeller::Context> impeller_context =
325 shell->GetIOManager()->GetImpellerContext();
329 impeller_context->StoreTaskForGPU([] {});
334 AddNativeCallback(
"FlushGpuAwaitingTasks",
337 ASSERT_TRUE(
shell->IsSetup());
339 configuration.SetEntrypoint(
"toByteDataWithoutGPU");
341 shell->RunEngine(std::move(configuration), [&](
auto result) {
345 message_latch.
Wait();
346 DestroyShell(std::move(shell), task_runners);
349TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImage16Float) {
351 EXPECT_CALL(*
image, dimensions)
355 auto texture = std::make_shared<MockTexture>(desc);
356 EXPECT_CALL(*
image, impeller_texture).WillOnce(Return(
texture));
357 std::vector<uint8_t>
buffer;
358 buffer.reserve(100 * 100 * 8);
359 auto context = MakeConvertDlImageToSkImageContext(
buffer);
360 bool did_call =
false;
365 ASSERT_TRUE(
image.ok());
366 ASSERT_TRUE(
image.value());
376TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImage10XR) {
378 EXPECT_CALL(*
image, dimensions)
382 auto texture = std::make_shared<MockTexture>(desc);
383 EXPECT_CALL(*
image, impeller_texture).WillOnce(Return(
texture));
384 std::vector<uint8_t>
buffer;
385 buffer.reserve(100 * 100 * 4);
386 auto context = MakeConvertDlImageToSkImageContext(
buffer);
387 bool did_call =
false;
392 ASSERT_TRUE(
image.ok());
393 ASSERT_TRUE(
image.value());
403TEST(ImageEncodingImpellerTest, PngEncoding10XR) {
414 paint.setAntiAlias(
true);
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
#define TEST(S, s, D, expected)
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
@ kBGR_101010x_XR_SkColorType
pixel with 10 bits each for blue, green, red; in 32-bit word, extended range
constexpr SkColor SK_ColorBLUE
constexpr SkColor SK_ColorWHITE
void clear(SkColor color)
void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint &paint)
SkColorSpace * colorSpace() const
SkColorType colorType() const
sk_sp< DlImage > image() const
static void ConvertDlImageToSkImage(const sk_sp< DlImage > &dl_image, std::function< void(fml::StatusOr< sk_sp< SkImage > >)> encode_task, const std::shared_ptr< impeller::Context > &impeller_context)
static RunConfiguration InferFromSettings(const Settings &settings, const fml::RefPtr< fml::TaskRunner > &io_worker=nullptr, IsolateLaunchType launch_type=IsolateLaunchType::kNewGroup)
Attempts to infer a run configuration from the settings object. This tries to create a run configurat...
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
fml::WeakPtr< IOManager > GetIOManager() const
static UIDartState * Current()
MOCK_METHOD(void, Execute,(const Handlers &handlers),(const))
MOCK_METHOD(void, SetSwitch,(bool value))
virtual void PostTask(const fml::closure &task) override
static constexpr int32_t kMaxTasksAwaitingGPU
DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfExternalTypedData(Dart_Handle object)
DART_EXPORT bool Dart_IsBoolean(Dart_Handle object)
DART_EXPORT Dart_Handle Dart_IntegerToInt64(Dart_Handle integer, int64_t *value)
struct _Dart_Handle * Dart_Handle
DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args, int index)
DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj, int index, intptr_t *value)
struct _Dart_NativeArguments * Dart_NativeArguments
DART_EXPORT bool Dart_IsNull(Dart_Handle object)
DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char *str)
DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_GetField(Dart_Handle container, Dart_Handle name)
DART_EXPORT bool Dart_IsError(Dart_Handle handle)
DART_EXPORT const char * Dart_GetError(Dart_Handle handle)
DART_EXPORT Dart_Handle Dart_BooleanValue(Dart_Handle boolean_obj, bool *value)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
fml::RefPtr< fml::TaskRunner > CreateNewThread(const std::string &name)
fml::RefPtr< fml::TaskRunner > GetCurrentTaskRunner()
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
TEST_F(DisplayListTest, Defaults)
sk_sp< SkImage > ConvertToRasterUsingResourceContext(const sk_sp< SkImage > &image, const fml::WeakPtr< GrDirectContext > &resource_context, const std::shared_ptr< const SyncSwitch > &is_gpu_disabled_sync_switch)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent Remove all existing persistent cache This is mainly for debugging purposes such as reproducing the shader compilation jank trace to Write the timeline trace to a file at the specified path The file will be in Perfetto s proto format
Dart_Handle EncodeImage(CanvasImage *canvas_image, int format, Dart_Handle callback_handle)
static constexpr SkISize Make(int32_t w, int32_t h)
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
Handlers & SetIfTrue(const std::function< void()> &handler)
std::function< void()> true_handler
std::function< void()> false_handler
Handlers & SetIfFalse(const std::function< void()> &handler)
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
#define CREATE_NATIVE_ENTRY(native_entry)
#define EXPECT_TRUE(handle)