19#include "gmock/gmock.h"
20#include "gtest/gtest.h"
22#if IMPELLER_SUPPORTS_RENDERING
30#pragma GCC diagnostic ignored "-Wunreachable-code"
41 Handlers& SetIfTrue(
const std::function<
void()>&
handler) {
45 Handlers& SetIfFalse(
const std::function<
void()>&
handler) {
53 MOCK_METHOD(
void, Execute, (
const Handlers& handlers), (
const));
54 MOCK_METHOD(
void, SetSwitch, (
bool value));
59 auto native_encode_image = [&](Dart_NativeArguments
args) {
60 auto image_handle = Dart_GetNativeArgument(
args, 0);
62 Dart_GetField(image_handle, Dart_NewStringFromCString(
"_image"));
63 ASSERT_FALSE(Dart_IsError(image_handle)) << Dart_GetError(image_handle);
64 ASSERT_FALSE(Dart_IsNull(image_handle));
65 auto format_handle = Dart_GetNativeArgument(
args, 1);
66 auto callback_handle = Dart_GetNativeArgument(
args, 2);
69 Dart_Handle result = Dart_GetNativeInstanceField(
71 ASSERT_FALSE(Dart_IsError(result));
75 result = Dart_IntegerToInt64(format_handle, &
format);
76 ASSERT_FALSE(Dart_IsError(result));
79 ASSERT_TRUE(Dart_IsNull(result));
82 auto nativeValidateExternal = [&](Dart_NativeArguments
args) {
83 auto handle = Dart_GetNativeArgument(
args, 0);
85 auto typed_data_type = Dart_GetTypeOfExternalTypedData(handle);
86 EXPECT_EQ(typed_data_type, Dart_TypedData_kUint8);
91 Settings settings = CreateSettingsForFixture();
93 GetCurrentTaskRunner(),
100 AddNativeCallback(
"ValidateExternal",
103 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
105 ASSERT_TRUE(shell->IsSetup());
107 configuration.SetEntrypoint(
"encodeImageProducesExternalUint8List");
109 shell->RunEngine(std::move(configuration), [&](
auto result) {
113 message_latch.
Wait();
114 DestroyShell(std::move(shell), task_runners);
118 Settings settings = CreateSettingsForFixture();
120 GetCurrentTaskRunner(),
126 auto native_encode_image = [&](Dart_NativeArguments
args) {
127 auto image_handle = Dart_GetNativeArgument(
args, 0);
129 Dart_GetField(image_handle, Dart_NewStringFromCString(
"_image"));
130 ASSERT_FALSE(Dart_IsError(image_handle)) << Dart_GetError(image_handle);
131 ASSERT_FALSE(Dart_IsNull(image_handle));
132 auto format_handle = Dart_GetNativeArgument(
args, 1);
135 Dart_Handle result = Dart_GetNativeInstanceField(
137 ASSERT_FALSE(Dart_IsError(result));
141 result = Dart_IntegerToInt64(format_handle, &
format);
142 ASSERT_FALSE(Dart_IsError(result));
148 auto is_gpu_disabled_sync_switch =
149 std::make_shared<const MockSyncSwitch>();
150 EXPECT_CALL(*is_gpu_disabled_sync_switch, Execute)
151 .WillOnce([](
const MockSyncSwitch::Handlers& handlers) {
152 handlers.true_handler();
154 auto skia_image = canvas_image->
image()
155 ? canvas_image->
image()->asSkiaImage()
158 skia_image ? skia_image->skia_image() :
nullptr,
159 io_manager->GetResourceContext(), is_gpu_disabled_sync_switch);
171 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
173 ASSERT_TRUE(shell->IsSetup());
175 configuration.SetEntrypoint(
"encodeImageProducesExternalUint8List");
177 shell->RunEngine(std::move(configuration), [&](
auto result) {
181 message_latch.
Wait();
182 DestroyShell(std::move(shell), task_runners);
185#if IMPELLER_SUPPORTS_RENDERING
186using ::impeller::testing::MockAllocator;
187using ::impeller::testing::MockBlitPass;
188using ::impeller::testing::MockCommandBuffer;
189using ::impeller::testing::MockCommandQueue;
190using ::impeller::testing::MockDeviceBuffer;
191using ::impeller::testing::MockImpellerContext;
192using ::impeller::testing::MockTexture;
194using ::testing::DoAll;
195using ::testing::Invoke;
196using ::testing::InvokeArgument;
197using ::testing::Return;
200std::shared_ptr<impeller::Context> MakeConvertDlImageToSkImageContext(
201 std::vector<uint8_t>& buffer) {
202 auto context = std::make_shared<MockImpellerContext>();
203 auto command_buffer = std::make_shared<MockCommandBuffer>(context);
204 auto allocator = std::make_shared<MockAllocator>();
205 auto blit_pass = std::make_shared<MockBlitPass>();
206 auto command_queue = std::make_shared<MockCommandQueue>();
209 auto device_buffer = std::make_shared<MockDeviceBuffer>(device_buffer_desc);
210 EXPECT_CALL(*
allocator, OnCreateBuffer).WillOnce(Return(device_buffer));
211 EXPECT_CALL(*blit_pass, IsValid).WillRepeatedly(Return(
true));
212 EXPECT_CALL(*command_buffer, IsValid).WillRepeatedly(Return(
true));
213 EXPECT_CALL(*command_buffer, OnCreateBlitPass).WillOnce(Return(blit_pass));
214 EXPECT_CALL(*context, GetResourceAllocator).WillRepeatedly(Return(
allocator));
216 EXPECT_CALL(*device_buffer, OnGetContents).WillOnce(Return(
buffer.data()));
217 EXPECT_CALL(*command_queue, Submit(_, _, _))
221 EXPECT_CALL(*context, GetCommandQueue).WillRepeatedly(Return(command_queue));
226TEST_F(ShellTest, EncodeImageRetries) {
228 GTEST_SKIP() <<
"Only works on macos currently.";
230 Settings settings = CreateSettingsForFixture();
231 settings.enable_impeller =
true;
232 TaskRunners task_runners(
"test",
239 std::unique_ptr<Shell> shell = CreateShell({
240 .settings = settings,
241 .task_runners = task_runners,
244 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
245 auto handle = Dart_GetNativeArgument(
args, 0);
247 ASSERT_TRUE(Dart_IsBoolean(handle));
248 Dart_BooleanValue(handle, &value);
249 TurnOffGPU(shell.get(), value);
254 auto validate_not_null = [&](Dart_NativeArguments
args) {
255 auto handle = Dart_GetNativeArgument(
args, 0);
256 EXPECT_FALSE(Dart_IsNull(handle));
262 ASSERT_TRUE(shell->IsSetup());
265 configuration.SetEntrypoint(
"toByteDataRetries");
267 shell->RunEngine(std::move(configuration), [&](
auto result) {
271 message_latch.
Wait();
272 DestroyShell(std::move(shell), task_runners);
275TEST_F(ShellTest, EncodeImageRetryOverflows) {
277 GTEST_SKIP() <<
"Only works on macos currently.";
279 Settings settings = CreateSettingsForFixture();
280 settings.enable_impeller =
true;
281 TaskRunners task_runners(
"test",
288 std::unique_ptr<Shell> shell = CreateShell({
289 .settings = settings,
290 .task_runners = task_runners,
293 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
294 auto handle = Dart_GetNativeArgument(
args, 0);
296 ASSERT_TRUE(Dart_IsBoolean(handle));
297 Dart_BooleanValue(handle, &value);
298 TurnOffGPU(shell.get(), value);
303 auto validate_not_null = [&](Dart_NativeArguments
args) {
304 auto handle = Dart_GetNativeArgument(
args, 0);
305 EXPECT_FALSE(Dart_IsNull(handle));
311 ASSERT_TRUE(shell->IsSetup());
314 configuration.SetEntrypoint(
"toByteDataRetryOverflows");
316 shell->RunEngine(std::move(configuration), [&](
auto result) {
320 message_latch.
Wait();
321 DestroyShell(std::move(shell), task_runners);
324TEST_F(ShellTest, ToImageRetries) {
326 GTEST_SKIP() <<
"Only works on macos currently.";
328 Settings settings = CreateSettingsForFixture();
329 settings.enable_impeller =
true;
330 TaskRunners task_runners(
"test",
337 std::unique_ptr<Shell> shell = CreateShell({
338 .settings = settings,
339 .task_runners = task_runners,
342 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
343 auto handle = Dart_GetNativeArgument(
args, 0);
345 ASSERT_TRUE(Dart_IsBoolean(handle));
346 Dart_BooleanValue(handle, &value);
347 TurnOffGPU(shell.get(), value);
352 auto validate_not_null = [&](Dart_NativeArguments
args) {
353 auto handle = Dart_GetNativeArgument(
args, 0);
354 EXPECT_FALSE(Dart_IsNull(handle));
360 ASSERT_TRUE(shell->IsSetup());
362 configuration.SetEntrypoint(
"toImageRetries");
364 shell->RunEngine(std::move(configuration), [&](
auto result) {
368 message_latch.
Wait();
369 DestroyShell(std::move(shell), task_runners);
371TEST_F(ShellTest, ToImageRetryOverflow) {
373 GTEST_SKIP() <<
"Only works on macos currently.";
375 Settings settings = CreateSettingsForFixture();
376 settings.enable_impeller =
true;
377 TaskRunners task_runners(
"test",
384 std::unique_ptr<Shell> shell = CreateShell({
385 .settings = settings,
386 .task_runners = task_runners,
389 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
390 auto handle = Dart_GetNativeArgument(
args, 0);
392 ASSERT_TRUE(Dart_IsBoolean(handle));
393 Dart_BooleanValue(handle, &value);
394 TurnOffGPU(shell.get(), value);
399 auto validate_not_null = [&](Dart_NativeArguments
args) {
400 auto handle = Dart_GetNativeArgument(
args, 0);
401 EXPECT_FALSE(Dart_IsNull(handle));
407 ASSERT_TRUE(shell->IsSetup());
409 configuration.SetEntrypoint(
"toImageRetryOverflows");
411 shell->RunEngine(std::move(configuration), [&](
auto result) {
415 message_latch.
Wait();
416 DestroyShell(std::move(shell), task_runners);
419TEST_F(ShellTest, EncodeImageFailsWithoutGPUImpeller) {
424 Settings settings = CreateSettingsForFixture();
425 settings.enable_impeller =
true;
426 TaskRunners task_runners(
"test",
433 auto native_validate_error = [&](Dart_NativeArguments
args) {
434 auto handle = Dart_GetNativeArgument(
args, 0);
436 EXPECT_FALSE(Dart_IsNull(handle));
441 AddNativeCallback(
"ValidateError",
444 std::unique_ptr<Shell> shell = CreateShell({
445 .settings = settings,
446 .task_runners = task_runners,
449 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
450 auto handle = Dart_GetNativeArgument(
args, 0);
452 ASSERT_TRUE(Dart_IsBoolean(handle));
453 Dart_BooleanValue(handle, &value);
454 TurnOffGPU(shell.get(),
true);
459 auto flush_awaiting_tasks = [&](Dart_NativeArguments
args) {
461 task_runners.GetIOTaskRunner()->PostTask([io_manager] {
463 std::shared_ptr<impeller::Context> impeller_context =
464 io_manager->GetImpellerContext();
468 impeller_context->StoreTaskForGPU([] {}, [] {});
474 AddNativeCallback(
"FlushGpuAwaitingTasks",
477 ASSERT_TRUE(shell->IsSetup());
479 configuration.SetEntrypoint(
"toByteDataWithoutGPU");
481 shell->RunEngine(std::move(configuration), [&](
auto result) {
485 message_latch.
Wait();
486 DestroyShell(std::move(shell), task_runners);
489TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImage16Float) {
490 sk_sp<MockDlImage>
image(
new MockDlImage());
491 EXPECT_CALL(*
image, GetSize)
492 .WillRepeatedly(Return(
DlISize(100, 100)));
496 auto texture = std::make_shared<MockTexture>(desc);
497 EXPECT_CALL(*
image, GetImpellerTexture(::testing::_))
499 std::vector<uint8_t>
buffer;
500 buffer.reserve(100 * 100 * 8);
501 auto context = MakeConvertDlImageToSkImageContext(buffer);
502 bool did_call =
false;
503 MockSnapshotDelegate snapshot_delegate;
504 EXPECT_CALL(snapshot_delegate, MakeRenderContextCurrent)
505 .WillRepeatedly(Return(
true));
510 ASSERT_TRUE(
image.ok());
511 ASSERT_TRUE(
image.value());
512 EXPECT_EQ(100,
image.value()->width());
513 EXPECT_EQ(100,
image.value()->height());
514 EXPECT_EQ(kRGBA_F16_SkColorType,
image.value()->colorType());
515 EXPECT_EQ(
nullptr,
image.value()->colorSpace());
517 snapshot_delegate.GetWeakPtr(), context);
518 EXPECT_TRUE(did_call);
521TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImage10XR) {
522 sk_sp<MockDlImage>
image(
new MockDlImage());
523 EXPECT_CALL(*
image, GetSize)
524 .WillRepeatedly(Return(
DlISize(100, 100)));
528 auto texture = std::make_shared<MockTexture>(desc);
529 EXPECT_CALL(*
image, GetImpellerTexture(::testing::_))
531 std::vector<uint8_t>
buffer;
532 buffer.reserve(100 * 100 * 4);
533 auto context = MakeConvertDlImageToSkImageContext(buffer);
534 bool did_call =
false;
535 MockSnapshotDelegate snapshot_delegate;
536 EXPECT_CALL(snapshot_delegate, MakeRenderContextCurrent)
537 .WillRepeatedly(Return(
true));
542 ASSERT_TRUE(
image.ok());
543 ASSERT_TRUE(
image.value());
544 EXPECT_EQ(100,
image.value()->width());
545 EXPECT_EQ(100,
image.value()->height());
546 EXPECT_EQ(kBGR_101010x_XR_SkColorType,
image.value()->colorType());
547 EXPECT_EQ(
nullptr,
image.value()->colorSpace());
549 snapshot_delegate.GetWeakPtr(), context);
550 EXPECT_TRUE(did_call);
553TEST(ImageEncodingImpellerTest, PngEncoding10XR) {
556 SkImageInfo info = SkImageInfo::Make(
557 width,
height, kBGR_101010x_XR_SkColorType, kUnpremul_SkAlphaType);
559 auto surface = SkSurfaces::Raster(info);
560 SkCanvas* canvas =
surface->getCanvas();
563 paint.setColor(SK_ColorBLUE);
564 paint.setAntiAlias(
true);
566 canvas->clear(SK_ColorWHITE);
567 canvas->drawCircle(
width / 2,
height / 2, 100, paint);
572 EXPECT_TRUE(
png.ok());
576struct PngMemoryReader {
582void PngMemoryRead(png_structp png_ptr,
584 png_size_t byte_count_to_read) {
585 PngMemoryReader* memory_reader =
586 reinterpret_cast<PngMemoryReader*
>(png_get_io_ptr(png_ptr));
587 if (memory_reader->offset + byte_count_to_read > memory_reader->size) {
588 png_error(png_ptr,
"Read error in PngMemoryRead");
590 memcpy(out_bytes, memory_reader->data + memory_reader->offset,
592 memory_reader->offset += byte_count_to_read;
598 png_create_read_struct(PNG_LIBPNG_VER_STRING,
nullptr,
nullptr,
nullptr);
603 png_infop info = png_create_info_struct(png);
605 png_destroy_read_struct(&png,
nullptr,
nullptr);
610 [&png, &info]() { png_destroy_read_struct(&png, &info,
nullptr); });
612 if (setjmp(png_jmpbuf(png))) {
616 PngMemoryReader memory_reader = {
617 .data = png_data, .offset = 0, .size = png_size};
618 png_set_read_fn(png, &memory_reader, PngMemoryRead);
620 png_read_info(png, info);
622 int width = png_get_image_width(png, info);
623 int height = png_get_image_height(png, info);
624 png_byte
color_type = png_get_color_type(png, info);
625 png_byte bit_depth = png_get_bit_depth(png, info);
627 if (bit_depth == 16) {
628 png_set_strip_16(png);
631 png_set_palette_to_rgb(png);
634 png_read_update_info(png, info);
636 std::vector<png_bytep> row_pointers;
637 row_pointers.reserve(
height);
640 row_pointers.push_back(
641 reinterpret_cast<png_bytep
>(result.data() +
i *
width));
644 png_read_image(png, row_pointers.data());
650TEST(ImageEncodingImpellerTest, PngEncodingBGRA10XR) {
653 SkImageInfo info = SkImageInfo::Make(
654 width,
height, kBGRA_10101010_XR_SkColorType, kUnpremul_SkAlphaType);
656 auto surface = SkSurfaces::Raster(info);
657 SkCanvas* canvas =
surface->getCanvas();
660 paint.setColor(SK_ColorBLUE);
661 paint.setAntiAlias(
true);
663 canvas->clear(SK_ColorRED);
664 canvas->drawCircle(
width / 2,
height / 2, 25, paint);
669 ASSERT_TRUE(
png.ok());
671 ReadPngFromMemory(
png.value()->bytes(),
png.value()->size());
672 ASSERT_TRUE(pixels.
ok());
673 EXPECT_EQ(pixels.
value()[0], 0xff0000ff);
674 int middle = 100 * 50 + 50;
675 EXPECT_EQ(pixels.
value()[middle], 0xffff0000);
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 fml::TaskRunnerAffineWeakPtr< SnapshotDelegate > &snapshot_delegate, 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()
Wraps a closure that is invoked in the destructor unless released by the caller.
virtual void PostTask(const fml::closure &task) override
static constexpr int32_t kMaxTasksAwaitingGPU
FlutterVulkanImage * image
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const gchar FlBinaryMessengerMessageHandler handler
uint32_t uint32_t * format
std::shared_ptr< ImpellerAllocator > allocator
std::function< void()> true_handler
std::function< void()> false_handler
fml::RefPtr< fml::TaskRunner > CreateNewThread(const std::string &name)
fml::RefPtr< fml::TaskRunner > GetCurrentTaskRunner()
TEST_F(DisplayListTest, Defaults)
TEST(NativeAssetsManagerTest, NoAvailableAssets)
impeller::ISize32 DlISize
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
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)
Dart_Handle EncodeImage(CanvasImage *canvas_image, int format, Dart_Handle callback_handle)
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 disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
static id< MTLCommandBuffer > CreateCommandBuffer(id< MTLCommandQueue > queue)
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
#define CREATE_NATIVE_ENTRY(native_entry)