18#include "gmock/gmock.h"
19#include "gtest/gtest.h"
21#if IMPELLER_SUPPORTS_RENDERING
29#pragma GCC diagnostic ignored "-Wunreachable-code"
40 Handlers& SetIfTrue(
const std::function<
void()>&
handler) {
44 Handlers& SetIfFalse(
const std::function<
void()>&
handler) {
52 MOCK_METHOD(
void, Execute, (
const Handlers& handlers), (
const));
53 MOCK_METHOD(
void, SetSwitch, (
bool value));
58 auto native_encode_image = [&](Dart_NativeArguments
args) {
59 auto image_handle = Dart_GetNativeArgument(
args, 0);
61 Dart_GetField(image_handle, Dart_NewStringFromCString(
"_image"));
62 ASSERT_FALSE(Dart_IsError(image_handle)) << Dart_GetError(image_handle);
63 ASSERT_FALSE(Dart_IsNull(image_handle));
64 auto format_handle = Dart_GetNativeArgument(
args, 1);
65 auto callback_handle = Dart_GetNativeArgument(
args, 2);
68 Dart_Handle result = Dart_GetNativeInstanceField(
70 ASSERT_FALSE(Dart_IsError(result));
74 result = Dart_IntegerToInt64(format_handle, &
format);
75 ASSERT_FALSE(Dart_IsError(result));
78 ASSERT_TRUE(Dart_IsNull(result));
81 auto nativeValidateExternal = [&](Dart_NativeArguments
args) {
82 auto handle = Dart_GetNativeArgument(
args, 0);
84 auto typed_data_type = Dart_GetTypeOfExternalTypedData(handle);
85 EXPECT_EQ(typed_data_type, Dart_TypedData_kUint8);
90 Settings settings = CreateSettingsForFixture();
92 GetCurrentTaskRunner(),
99 AddNativeCallback(
"ValidateExternal",
102 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
104 ASSERT_TRUE(shell->IsSetup());
106 configuration.SetEntrypoint(
"encodeImageProducesExternalUint8List");
108 shell->RunEngine(std::move(configuration), [&](
auto result) {
112 message_latch.
Wait();
113 DestroyShell(std::move(shell), task_runners);
117 Settings settings = CreateSettingsForFixture();
119 GetCurrentTaskRunner(),
125 auto native_encode_image = [&](Dart_NativeArguments
args) {
126 auto image_handle = Dart_GetNativeArgument(
args, 0);
128 Dart_GetField(image_handle, Dart_NewStringFromCString(
"_image"));
129 ASSERT_FALSE(Dart_IsError(image_handle)) << Dart_GetError(image_handle);
130 ASSERT_FALSE(Dart_IsNull(image_handle));
131 auto format_handle = Dart_GetNativeArgument(
args, 1);
134 Dart_Handle result = Dart_GetNativeInstanceField(
136 ASSERT_FALSE(Dart_IsError(result));
140 result = Dart_IntegerToInt64(format_handle, &
format);
141 ASSERT_FALSE(Dart_IsError(result));
147 auto is_gpu_disabled_sync_switch =
148 std::make_shared<const MockSyncSwitch>();
149 EXPECT_CALL(*is_gpu_disabled_sync_switch, Execute)
150 .WillOnce([](
const MockSyncSwitch::Handlers& handlers) {
151 handlers.true_handler();
154 io_manager->GetResourceContext(),
155 is_gpu_disabled_sync_switch);
166 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
168 ASSERT_TRUE(shell->IsSetup());
170 configuration.SetEntrypoint(
"encodeImageProducesExternalUint8List");
172 shell->RunEngine(std::move(configuration), [&](
auto result) {
176 message_latch.
Wait();
177 DestroyShell(std::move(shell), task_runners);
180#if IMPELLER_SUPPORTS_RENDERING
181using ::impeller::testing::MockAllocator;
182using ::impeller::testing::MockBlitPass;
183using ::impeller::testing::MockCommandBuffer;
184using ::impeller::testing::MockCommandQueue;
185using ::impeller::testing::MockDeviceBuffer;
186using ::impeller::testing::MockImpellerContext;
187using ::impeller::testing::MockTexture;
189using ::testing::DoAll;
190using ::testing::Invoke;
191using ::testing::InvokeArgument;
192using ::testing::Return;
195std::shared_ptr<impeller::Context> MakeConvertDlImageToSkImageContext(
196 std::vector<uint8_t>& buffer) {
197 auto context = std::make_shared<MockImpellerContext>();
198 auto command_buffer = std::make_shared<MockCommandBuffer>(context);
199 auto allocator = std::make_shared<MockAllocator>();
200 auto blit_pass = std::make_shared<MockBlitPass>();
201 auto command_queue = std::make_shared<MockCommandQueue>();
204 auto device_buffer = std::make_shared<MockDeviceBuffer>(device_buffer_desc);
205 EXPECT_CALL(*
allocator, OnCreateBuffer).WillOnce(Return(device_buffer));
206 EXPECT_CALL(*blit_pass, IsValid).WillRepeatedly(Return(
true));
207 EXPECT_CALL(*command_buffer, IsValid).WillRepeatedly(Return(
true));
208 EXPECT_CALL(*command_buffer, OnCreateBlitPass).WillOnce(Return(blit_pass));
209 EXPECT_CALL(*context, GetResourceAllocator).WillRepeatedly(Return(
allocator));
211 EXPECT_CALL(*device_buffer, OnGetContents).WillOnce(Return(
buffer.data()));
212 EXPECT_CALL(*command_queue, Submit(_, _, _))
216 EXPECT_CALL(*context, GetCommandQueue).WillRepeatedly(Return(command_queue));
221TEST_F(ShellTest, EncodeImageRetries) {
223 GTEST_SKIP() <<
"Only works on macos currently.";
225 Settings settings = CreateSettingsForFixture();
226 settings.enable_impeller =
true;
227 TaskRunners task_runners(
"test",
234 std::unique_ptr<Shell> shell = CreateShell({
235 .settings = settings,
236 .task_runners = task_runners,
239 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
240 auto handle = Dart_GetNativeArgument(
args, 0);
242 ASSERT_TRUE(Dart_IsBoolean(handle));
243 Dart_BooleanValue(handle, &value);
244 TurnOffGPU(shell.get(), value);
249 auto validate_not_null = [&](Dart_NativeArguments
args) {
250 auto handle = Dart_GetNativeArgument(
args, 0);
251 EXPECT_FALSE(Dart_IsNull(handle));
257 ASSERT_TRUE(shell->IsSetup());
260 configuration.SetEntrypoint(
"toByteDataRetries");
262 shell->RunEngine(std::move(configuration), [&](
auto result) {
266 message_latch.
Wait();
267 DestroyShell(std::move(shell), task_runners);
270TEST_F(ShellTest, EncodeImageRetryOverflows) {
272 GTEST_SKIP() <<
"Only works on macos currently.";
274 Settings settings = CreateSettingsForFixture();
275 settings.enable_impeller =
true;
276 TaskRunners task_runners(
"test",
283 std::unique_ptr<Shell> shell = CreateShell({
284 .settings = settings,
285 .task_runners = task_runners,
288 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
289 auto handle = Dart_GetNativeArgument(
args, 0);
291 ASSERT_TRUE(Dart_IsBoolean(handle));
292 Dart_BooleanValue(handle, &value);
293 TurnOffGPU(shell.get(), value);
298 auto validate_not_null = [&](Dart_NativeArguments
args) {
299 auto handle = Dart_GetNativeArgument(
args, 0);
300 EXPECT_FALSE(Dart_IsNull(handle));
306 ASSERT_TRUE(shell->IsSetup());
309 configuration.SetEntrypoint(
"toByteDataRetryOverflows");
311 shell->RunEngine(std::move(configuration), [&](
auto result) {
315 message_latch.
Wait();
316 DestroyShell(std::move(shell), task_runners);
319TEST_F(ShellTest, ToImageRetries) {
321 GTEST_SKIP() <<
"Only works on macos currently.";
323 Settings settings = CreateSettingsForFixture();
324 settings.enable_impeller =
true;
325 TaskRunners task_runners(
"test",
332 std::unique_ptr<Shell> shell = CreateShell({
333 .settings = settings,
334 .task_runners = task_runners,
337 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
338 auto handle = Dart_GetNativeArgument(
args, 0);
340 ASSERT_TRUE(Dart_IsBoolean(handle));
341 Dart_BooleanValue(handle, &value);
342 TurnOffGPU(shell.get(), value);
347 auto validate_not_null = [&](Dart_NativeArguments
args) {
348 auto handle = Dart_GetNativeArgument(
args, 0);
349 EXPECT_FALSE(Dart_IsNull(handle));
355 ASSERT_TRUE(shell->IsSetup());
357 configuration.SetEntrypoint(
"toImageRetries");
359 shell->RunEngine(std::move(configuration), [&](
auto result) {
363 message_latch.
Wait();
364 DestroyShell(std::move(shell), task_runners);
366TEST_F(ShellTest, ToImageRetryOverflow) {
368 GTEST_SKIP() <<
"Only works on macos currently.";
370 Settings settings = CreateSettingsForFixture();
371 settings.enable_impeller =
true;
372 TaskRunners task_runners(
"test",
379 std::unique_ptr<Shell> shell = CreateShell({
380 .settings = settings,
381 .task_runners = task_runners,
384 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
385 auto handle = Dart_GetNativeArgument(
args, 0);
387 ASSERT_TRUE(Dart_IsBoolean(handle));
388 Dart_BooleanValue(handle, &value);
389 TurnOffGPU(shell.get(), value);
394 auto validate_not_null = [&](Dart_NativeArguments
args) {
395 auto handle = Dart_GetNativeArgument(
args, 0);
396 EXPECT_FALSE(Dart_IsNull(handle));
402 ASSERT_TRUE(shell->IsSetup());
404 configuration.SetEntrypoint(
"toImageRetryOverflows");
406 shell->RunEngine(std::move(configuration), [&](
auto result) {
410 message_latch.
Wait();
411 DestroyShell(std::move(shell), task_runners);
414TEST_F(ShellTest, EncodeImageFailsWithoutGPUImpeller) {
419 Settings settings = CreateSettingsForFixture();
420 settings.enable_impeller =
true;
421 TaskRunners task_runners(
"test",
428 auto native_validate_error = [&](Dart_NativeArguments
args) {
429 auto handle = Dart_GetNativeArgument(
args, 0);
431 EXPECT_FALSE(Dart_IsNull(handle));
436 AddNativeCallback(
"ValidateError",
439 std::unique_ptr<Shell> shell = CreateShell({
440 .settings = settings,
441 .task_runners = task_runners,
444 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
445 auto handle = Dart_GetNativeArgument(
args, 0);
447 ASSERT_TRUE(Dart_IsBoolean(handle));
448 Dart_BooleanValue(handle, &value);
449 TurnOffGPU(shell.get(),
true);
454 auto flush_awaiting_tasks = [&](Dart_NativeArguments
args) {
456 task_runners.GetIOTaskRunner()->PostTask([io_manager] {
458 std::shared_ptr<impeller::Context> impeller_context =
459 io_manager->GetImpellerContext();
463 impeller_context->StoreTaskForGPU([] {}, [] {});
469 AddNativeCallback(
"FlushGpuAwaitingTasks",
472 ASSERT_TRUE(shell->IsSetup());
474 configuration.SetEntrypoint(
"toByteDataWithoutGPU");
476 shell->RunEngine(std::move(configuration), [&](
auto result) {
480 message_latch.
Wait();
481 DestroyShell(std::move(shell), task_runners);
484TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImage16Float) {
485 sk_sp<MockDlImage>
image(
new MockDlImage());
486 EXPECT_CALL(*
image, GetSize)
487 .WillRepeatedly(Return(
DlISize(100, 100)));
490 auto texture = std::make_shared<MockTexture>(desc);
491 EXPECT_CALL(*
image, impeller_texture).WillOnce(Return(
texture));
492 std::vector<uint8_t>
buffer;
493 buffer.reserve(100 * 100 * 8);
494 auto context = MakeConvertDlImageToSkImageContext(buffer);
495 bool did_call =
false;
496 MockSnapshotDelegate snapshot_delegate;
497 EXPECT_CALL(snapshot_delegate, MakeRenderContextCurrent)
498 .WillRepeatedly(Return(
true));
503 ASSERT_TRUE(
image.ok());
504 ASSERT_TRUE(
image.value());
505 EXPECT_EQ(100,
image.value()->width());
506 EXPECT_EQ(100,
image.value()->height());
507 EXPECT_EQ(kRGBA_F16_SkColorType,
image.value()->colorType());
508 EXPECT_EQ(
nullptr,
image.value()->colorSpace());
510 snapshot_delegate.GetWeakPtr(), context);
511 EXPECT_TRUE(did_call);
514TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImage10XR) {
515 sk_sp<MockDlImage>
image(
new MockDlImage());
516 EXPECT_CALL(*
image, GetSize)
517 .WillRepeatedly(Return(
DlISize(100, 100)));
520 auto texture = std::make_shared<MockTexture>(desc);
521 EXPECT_CALL(*
image, impeller_texture).WillOnce(Return(
texture));
522 std::vector<uint8_t>
buffer;
523 buffer.reserve(100 * 100 * 4);
524 auto context = MakeConvertDlImageToSkImageContext(buffer);
525 bool did_call =
false;
526 MockSnapshotDelegate snapshot_delegate;
527 EXPECT_CALL(snapshot_delegate, MakeRenderContextCurrent)
528 .WillRepeatedly(Return(
true));
533 ASSERT_TRUE(
image.ok());
534 ASSERT_TRUE(
image.value());
535 EXPECT_EQ(100,
image.value()->width());
536 EXPECT_EQ(100,
image.value()->height());
537 EXPECT_EQ(kBGR_101010x_XR_SkColorType,
image.value()->colorType());
538 EXPECT_EQ(
nullptr,
image.value()->colorSpace());
540 snapshot_delegate.GetWeakPtr(), context);
541 EXPECT_TRUE(did_call);
544TEST(ImageEncodingImpellerTest, PngEncoding10XR) {
547 SkImageInfo info = SkImageInfo::Make(
548 width,
height, kBGR_101010x_XR_SkColorType, kUnpremul_SkAlphaType);
550 auto surface = SkSurfaces::Raster(info);
551 SkCanvas* canvas =
surface->getCanvas();
554 paint.setColor(SK_ColorBLUE);
555 paint.setAntiAlias(
true);
557 canvas->clear(SK_ColorWHITE);
558 canvas->drawCircle(
width / 2,
height / 2, 100, paint);
563 EXPECT_TRUE(
png.ok());
567struct PngMemoryReader {
573void PngMemoryRead(png_structp png_ptr,
575 png_size_t byte_count_to_read) {
576 PngMemoryReader* memory_reader =
577 reinterpret_cast<PngMemoryReader*
>(png_get_io_ptr(png_ptr));
578 if (memory_reader->offset + byte_count_to_read > memory_reader->size) {
579 png_error(png_ptr,
"Read error in PngMemoryRead");
581 memcpy(out_bytes, memory_reader->data + memory_reader->offset,
583 memory_reader->offset += byte_count_to_read;
589 png_create_read_struct(PNG_LIBPNG_VER_STRING,
nullptr,
nullptr,
nullptr);
594 png_infop info = png_create_info_struct(png);
596 png_destroy_read_struct(&png,
nullptr,
nullptr);
601 [&png, &info]() { png_destroy_read_struct(&png, &info,
nullptr); });
603 if (setjmp(png_jmpbuf(png))) {
607 PngMemoryReader memory_reader = {
608 .data = png_data, .offset = 0, .size = png_size};
609 png_set_read_fn(png, &memory_reader, PngMemoryRead);
611 png_read_info(png, info);
613 int width = png_get_image_width(png, info);
614 int height = png_get_image_height(png, info);
615 png_byte
color_type = png_get_color_type(png, info);
616 png_byte bit_depth = png_get_bit_depth(png, info);
618 if (bit_depth == 16) {
619 png_set_strip_16(png);
622 png_set_palette_to_rgb(png);
625 png_read_update_info(png, info);
627 std::vector<png_bytep> row_pointers;
628 row_pointers.reserve(
height);
631 row_pointers.push_back(
632 reinterpret_cast<png_bytep
>(result.data() +
i *
width));
635 png_read_image(png, row_pointers.data());
641TEST(ImageEncodingImpellerTest, PngEncodingBGRA10XR) {
644 SkImageInfo info = SkImageInfo::Make(
645 width,
height, kBGRA_10101010_XR_SkColorType, kUnpremul_SkAlphaType);
647 auto surface = SkSurfaces::Raster(info);
648 SkCanvas* canvas =
surface->getCanvas();
651 paint.setColor(SK_ColorBLUE);
652 paint.setAntiAlias(
true);
654 canvas->clear(SK_ColorRED);
655 canvas->drawCircle(
width / 2,
height / 2, 25, paint);
660 ASSERT_TRUE(
png.ok());
662 ReadPngFromMemory(
png.value()->bytes(),
png.value()->size());
663 ASSERT_TRUE(pixels.
ok());
664 EXPECT_EQ(pixels.
value()[0], 0xff0000ff);
665 int middle = 100 * 50 + 50;
666 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
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)
std::shared_ptr< const fml::Mapping > data