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>();
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);
499 EXPECT_CALL(*
image, GetImpellerTexture(::testing::_))
501 std::vector<uint8_t>
buffer;
502 buffer.reserve(100 * 100 * 8);
503 auto context = MakeConvertDlImageToSkImageContext(buffer);
504 bool did_call =
false;
505 MockSnapshotDelegate snapshot_delegate;
506 EXPECT_CALL(snapshot_delegate, MakeRenderContextCurrent)
507 .WillRepeatedly(Return(
true));
512 ASSERT_TRUE(
image.ok());
513 ASSERT_TRUE(
image.value());
514 EXPECT_EQ(100,
image.value()->width());
515 EXPECT_EQ(100,
image.value()->height());
516 EXPECT_EQ(kRGBA_F16_SkColorType,
image.value()->colorType());
517 EXPECT_EQ(
nullptr,
image.value()->colorSpace());
519 snapshot_delegate.GetWeakPtr(),
context);
520 EXPECT_TRUE(did_call);
523TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImage10XR) {
524 sk_sp<MockDlImage>
image(
new MockDlImage());
525 EXPECT_CALL(*
image, GetSize)
526 .WillRepeatedly(Return(
DlISize(100, 100)));
530 auto texture = std::make_shared<MockTexture>(desc);
533 EXPECT_CALL(*
image, GetImpellerTexture(::testing::_))
535 std::vector<uint8_t>
buffer;
536 buffer.reserve(100 * 100 * 4);
537 auto context = MakeConvertDlImageToSkImageContext(buffer);
538 bool did_call =
false;
539 MockSnapshotDelegate snapshot_delegate;
540 EXPECT_CALL(snapshot_delegate, MakeRenderContextCurrent)
541 .WillRepeatedly(Return(
true));
546 ASSERT_TRUE(
image.ok());
547 ASSERT_TRUE(
image.value());
548 EXPECT_EQ(100,
image.value()->width());
549 EXPECT_EQ(100,
image.value()->height());
550 EXPECT_EQ(kBGR_101010x_XR_SkColorType,
image.value()->colorType());
551 EXPECT_EQ(
nullptr,
image.value()->colorSpace());
553 snapshot_delegate.GetWeakPtr(),
context);
554 EXPECT_TRUE(did_call);
557TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImageTextureSizeMismatch) {
558 DlISize dl_image_size(100, 100);
559 sk_sp<MockDlImage>
image(
new MockDlImage());
560 EXPECT_CALL(*
image, GetSize)
561 .WillRepeatedly(Return(dl_image_size));
567 auto texture = std::make_shared<MockTexture>(desc);
568 EXPECT_CALL(*
texture, GetSize).WillRepeatedly(Return(desc.
size));
569 EXPECT_CALL(*
image, GetImpellerTexture(::testing::_))
571 std::vector<uint8_t>
buffer;
574 auto context = MakeConvertDlImageToSkImageContext(buffer);
576 bool did_call =
false;
577 MockSnapshotDelegate snapshot_delegate;
578 EXPECT_CALL(snapshot_delegate, MakeRenderContextCurrent)
579 .WillRepeatedly(Return(
true));
584 ASSERT_TRUE(result.ok());
585 ASSERT_TRUE(result.value());
588 EXPECT_EQ(desc.
size.
width, result.value()->width());
589 EXPECT_EQ(desc.
size.
height, result.value()->height());
591 snapshot_delegate.GetWeakPtr(),
context);
592 EXPECT_TRUE(did_call);
595TEST(ImageEncodingImpellerTest, PngEncoding10XR) {
598 SkImageInfo info = SkImageInfo::Make(
599 width,
height, kBGR_101010x_XR_SkColorType, kUnpremul_SkAlphaType);
601 auto surface = SkSurfaces::Raster(info);
602 SkCanvas* canvas =
surface->getCanvas();
605 paint.setColor(SK_ColorBLUE);
606 paint.setAntiAlias(
true);
608 canvas->clear(SK_ColorWHITE);
609 canvas->drawCircle(
width / 2,
height / 2, 100, paint);
614 EXPECT_TRUE(
png.ok());
618struct PngMemoryReader {
624void PngMemoryRead(png_structp png_ptr,
626 png_size_t byte_count_to_read) {
627 PngMemoryReader* memory_reader =
628 reinterpret_cast<PngMemoryReader*
>(png_get_io_ptr(png_ptr));
629 if (memory_reader->offset + byte_count_to_read > memory_reader->size) {
630 png_error(png_ptr,
"Read error in PngMemoryRead");
632 memcpy(out_bytes, memory_reader->data + memory_reader->offset,
634 memory_reader->offset += byte_count_to_read;
640 png_create_read_struct(PNG_LIBPNG_VER_STRING,
nullptr,
nullptr,
nullptr);
645 png_infop info = png_create_info_struct(png);
647 png_destroy_read_struct(&png,
nullptr,
nullptr);
652 [&png, &info]() { png_destroy_read_struct(&png, &info,
nullptr); });
654 if (setjmp(png_jmpbuf(png))) {
658 PngMemoryReader memory_reader = {
659 .data = png_data, .offset = 0, .size = png_size};
660 png_set_read_fn(png, &memory_reader, PngMemoryRead);
662 png_read_info(png, info);
664 int width = png_get_image_width(png, info);
665 int height = png_get_image_height(png, info);
666 png_byte
color_type = png_get_color_type(png, info);
667 png_byte bit_depth = png_get_bit_depth(png, info);
669 if (bit_depth == 16) {
670 png_set_strip_16(png);
673 png_set_palette_to_rgb(png);
676 png_read_update_info(png, info);
678 std::vector<png_bytep> row_pointers;
679 row_pointers.reserve(
height);
682 row_pointers.push_back(
683 reinterpret_cast<png_bytep
>(result.data() +
i *
width));
686 png_read_image(png, row_pointers.data());
692TEST(ImageEncodingImpellerTest, PngEncodingBGRA10XR) {
695 SkImageInfo info = SkImageInfo::Make(
696 width,
height, kBGRA_10101010_XR_SkColorType, kUnpremul_SkAlphaType);
698 auto surface = SkSurfaces::Raster(info);
699 SkCanvas* canvas =
surface->getCanvas();
702 paint.setColor(SK_ColorBLUE);
703 paint.setAntiAlias(
true);
705 canvas->clear(SK_ColorRED);
706 canvas->drawCircle(
width / 2,
height / 2, 25, paint);
711 ASSERT_TRUE(
png.ok());
713 ReadPngFromMemory(
png.value()->bytes(),
png.value()->size());
714 ASSERT_TRUE(pixels.
ok());
715 EXPECT_EQ(pixels.
value()[0], 0xff0000ff);
716 int middle = 100 * 50 + 50;
717 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
constexpr size_t BytesPerPixelForPixelFormat(PixelFormat format)
static id< MTLCommandBuffer > CreateCommandBuffer(id< MTLCommandQueue > queue)
std::shared_ptr< ContextGLES > context
std::shared_ptr< CommandBuffer > command_buffer
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
#define CREATE_NATIVE_ENTRY(native_entry)