18#include "gmock/gmock.h"
19#include "gtest/gtest.h"
21#if IMPELLER_SUPPORTS_RENDERING
29#pragma GCC diagnostic ignored "-Wunreachable-code"
37class MockDlImage :
public DlImage {
39 MOCK_METHOD(sk_sp<SkImage>, skia_image, (), (
const,
override));
40 MOCK_METHOD(std::shared_ptr<impeller::Texture>,
44 MOCK_METHOD(
bool, isOpaque, (), (
const,
override));
45 MOCK_METHOD(
bool, isTextureBacked, (), (
const,
override));
46 MOCK_METHOD(
bool, isUIThreadSafe, (), (
const,
override));
47 MOCK_METHOD(
DlISize, GetSize, (), (
const,
override));
48 MOCK_METHOD(
size_t, GetApproximateByteSize, (), (
const,
override));
78 (sk_sp<DisplayList>,
const SkImageInfo&),
89 std::function<
void(sk_sp<DlImage>)>),
101 (
const std::shared_ptr<impeller::RuntimeStage>&),
106 return weak_factory_.GetWeakPtr();
114 auto native_encode_image = [&](Dart_NativeArguments
args) {
115 auto image_handle = Dart_GetNativeArgument(
args, 0);
117 Dart_GetField(image_handle, Dart_NewStringFromCString(
"_image"));
118 ASSERT_FALSE(Dart_IsError(image_handle)) << Dart_GetError(image_handle);
119 ASSERT_FALSE(Dart_IsNull(image_handle));
120 auto format_handle = Dart_GetNativeArgument(
args, 1);
121 auto callback_handle = Dart_GetNativeArgument(
args, 2);
124 Dart_Handle result = Dart_GetNativeInstanceField(
126 ASSERT_FALSE(Dart_IsError(result));
130 result = Dart_IntegerToInt64(format_handle, &
format);
131 ASSERT_FALSE(Dart_IsError(result));
134 ASSERT_TRUE(Dart_IsNull(result));
137 auto nativeValidateExternal = [&](Dart_NativeArguments
args) {
138 auto handle = Dart_GetNativeArgument(
args, 0);
140 auto typed_data_type = Dart_GetTypeOfExternalTypedData(handle);
141 EXPECT_EQ(typed_data_type, Dart_TypedData_kUint8);
146 Settings settings = CreateSettingsForFixture();
148 GetCurrentTaskRunner(),
155 AddNativeCallback(
"ValidateExternal",
158 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
160 ASSERT_TRUE(shell->IsSetup());
162 configuration.SetEntrypoint(
"encodeImageProducesExternalUint8List");
164 shell->RunEngine(std::move(configuration), [&](
auto result) {
168 message_latch.
Wait();
169 DestroyShell(std::move(shell), task_runners);
173 Settings settings = CreateSettingsForFixture();
175 GetCurrentTaskRunner(),
181 auto native_encode_image = [&](Dart_NativeArguments
args) {
182 auto image_handle = Dart_GetNativeArgument(
args, 0);
184 Dart_GetField(image_handle, Dart_NewStringFromCString(
"_image"));
185 ASSERT_FALSE(Dart_IsError(image_handle)) << Dart_GetError(image_handle);
186 ASSERT_FALSE(Dart_IsNull(image_handle));
187 auto format_handle = Dart_GetNativeArgument(
args, 1);
190 Dart_Handle result = Dart_GetNativeInstanceField(
192 ASSERT_FALSE(Dart_IsError(result));
196 result = Dart_IntegerToInt64(format_handle, &
format);
197 ASSERT_FALSE(Dart_IsError(result));
203 auto is_gpu_disabled_sync_switch =
204 std::make_shared<const MockSyncSwitch>();
205 EXPECT_CALL(*is_gpu_disabled_sync_switch, Execute)
210 io_manager->GetResourceContext(),
211 is_gpu_disabled_sync_switch);
222 std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
224 ASSERT_TRUE(shell->IsSetup());
226 configuration.SetEntrypoint(
"encodeImageProducesExternalUint8List");
228 shell->RunEngine(std::move(configuration), [&](
auto result) {
232 message_latch.
Wait();
233 DestroyShell(std::move(shell), task_runners);
236#if IMPELLER_SUPPORTS_RENDERING
237using ::impeller::testing::MockAllocator;
238using ::impeller::testing::MockBlitPass;
239using ::impeller::testing::MockCommandBuffer;
240using ::impeller::testing::MockCommandQueue;
241using ::impeller::testing::MockDeviceBuffer;
242using ::impeller::testing::MockImpellerContext;
243using ::impeller::testing::MockTexture;
245using ::testing::DoAll;
246using ::testing::Invoke;
247using ::testing::InvokeArgument;
248using ::testing::Return;
251std::shared_ptr<impeller::Context> MakeConvertDlImageToSkImageContext(
252 std::vector<uint8_t>& buffer) {
253 auto context = std::make_shared<MockImpellerContext>();
254 auto command_buffer = std::make_shared<MockCommandBuffer>(context);
255 auto allocator = std::make_shared<MockAllocator>();
256 auto blit_pass = std::make_shared<MockBlitPass>();
257 auto command_queue = std::make_shared<MockCommandQueue>();
260 auto device_buffer = std::make_shared<MockDeviceBuffer>(device_buffer_desc);
261 EXPECT_CALL(*allocator, OnCreateBuffer).WillOnce(Return(device_buffer));
262 EXPECT_CALL(*blit_pass, IsValid).WillRepeatedly(Return(
true));
263 EXPECT_CALL(*command_buffer, IsValid).WillRepeatedly(Return(
true));
264 EXPECT_CALL(*command_buffer, OnCreateBlitPass).WillOnce(Return(blit_pass));
265 EXPECT_CALL(*context, GetResourceAllocator).WillRepeatedly(Return(allocator));
267 EXPECT_CALL(*device_buffer, OnGetContents).WillOnce(Return(
buffer.data()));
268 EXPECT_CALL(*command_queue, Submit(_, _, _))
272 EXPECT_CALL(*context, GetCommandQueue).WillRepeatedly(Return(command_queue));
277TEST_F(ShellTest, EncodeImageRetries) {
279 GTEST_SKIP() <<
"Only works on macos currently.";
281 Settings settings = CreateSettingsForFixture();
282 settings.enable_impeller =
true;
283 TaskRunners task_runners(
"test",
290 std::unique_ptr<Shell> shell = CreateShell({
291 .settings = settings,
292 .task_runners = task_runners,
295 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
296 auto handle = Dart_GetNativeArgument(
args, 0);
298 ASSERT_TRUE(Dart_IsBoolean(handle));
299 Dart_BooleanValue(handle, &value);
300 TurnOffGPU(shell.get(), value);
305 auto validate_not_null = [&](Dart_NativeArguments
args) {
306 auto handle = Dart_GetNativeArgument(
args, 0);
307 EXPECT_FALSE(Dart_IsNull(handle));
313 ASSERT_TRUE(shell->IsSetup());
316 configuration.SetEntrypoint(
"toByteDataRetries");
318 shell->RunEngine(std::move(configuration), [&](
auto result) {
322 message_latch.
Wait();
323 DestroyShell(std::move(shell), task_runners);
326TEST_F(ShellTest, EncodeImageRetryOverflows) {
328 GTEST_SKIP() <<
"Only works on macos currently.";
330 Settings settings = CreateSettingsForFixture();
331 settings.enable_impeller =
true;
332 TaskRunners task_runners(
"test",
339 std::unique_ptr<Shell> shell = CreateShell({
340 .settings = settings,
341 .task_runners = task_runners,
344 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
345 auto handle = Dart_GetNativeArgument(
args, 0);
347 ASSERT_TRUE(Dart_IsBoolean(handle));
348 Dart_BooleanValue(handle, &value);
349 TurnOffGPU(shell.get(), value);
354 auto validate_not_null = [&](Dart_NativeArguments
args) {
355 auto handle = Dart_GetNativeArgument(
args, 0);
356 EXPECT_FALSE(Dart_IsNull(handle));
362 ASSERT_TRUE(shell->IsSetup());
365 configuration.SetEntrypoint(
"toByteDataRetryOverflows");
367 shell->RunEngine(std::move(configuration), [&](
auto result) {
371 message_latch.
Wait();
372 DestroyShell(std::move(shell), task_runners);
375TEST_F(ShellTest, ToImageRetries) {
377 GTEST_SKIP() <<
"Only works on macos currently.";
379 Settings settings = CreateSettingsForFixture();
380 settings.enable_impeller =
true;
381 TaskRunners task_runners(
"test",
388 std::unique_ptr<Shell> shell = CreateShell({
389 .settings = settings,
390 .task_runners = task_runners,
393 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
394 auto handle = Dart_GetNativeArgument(
args, 0);
396 ASSERT_TRUE(Dart_IsBoolean(handle));
397 Dart_BooleanValue(handle, &value);
398 TurnOffGPU(shell.get(), value);
403 auto validate_not_null = [&](Dart_NativeArguments
args) {
404 auto handle = Dart_GetNativeArgument(
args, 0);
405 EXPECT_FALSE(Dart_IsNull(handle));
411 ASSERT_TRUE(shell->IsSetup());
413 configuration.SetEntrypoint(
"toImageRetries");
415 shell->RunEngine(std::move(configuration), [&](
auto result) {
419 message_latch.
Wait();
420 DestroyShell(std::move(shell), task_runners);
422TEST_F(ShellTest, ToImageRetryOverflow) {
424 GTEST_SKIP() <<
"Only works on macos currently.";
426 Settings settings = CreateSettingsForFixture();
427 settings.enable_impeller =
true;
428 TaskRunners task_runners(
"test",
435 std::unique_ptr<Shell> shell = CreateShell({
436 .settings = settings,
437 .task_runners = task_runners,
440 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
441 auto handle = Dart_GetNativeArgument(
args, 0);
443 ASSERT_TRUE(Dart_IsBoolean(handle));
444 Dart_BooleanValue(handle, &value);
445 TurnOffGPU(shell.get(), value);
450 auto validate_not_null = [&](Dart_NativeArguments
args) {
451 auto handle = Dart_GetNativeArgument(
args, 0);
452 EXPECT_FALSE(Dart_IsNull(handle));
458 ASSERT_TRUE(shell->IsSetup());
460 configuration.SetEntrypoint(
"toImageRetryOverflows");
462 shell->RunEngine(std::move(configuration), [&](
auto result) {
466 message_latch.
Wait();
467 DestroyShell(std::move(shell), task_runners);
470TEST_F(ShellTest, EncodeImageFailsWithoutGPUImpeller) {
475 Settings settings = CreateSettingsForFixture();
476 settings.enable_impeller =
true;
477 TaskRunners task_runners(
"test",
484 auto native_validate_error = [&](Dart_NativeArguments
args) {
485 auto handle = Dart_GetNativeArgument(
args, 0);
487 EXPECT_FALSE(Dart_IsNull(handle));
492 AddNativeCallback(
"ValidateError",
495 std::unique_ptr<Shell> shell = CreateShell({
496 .settings = settings,
497 .task_runners = task_runners,
500 auto turn_off_gpu = [&](Dart_NativeArguments
args) {
501 auto handle = Dart_GetNativeArgument(
args, 0);
503 ASSERT_TRUE(Dart_IsBoolean(handle));
504 Dart_BooleanValue(handle, &value);
505 TurnOffGPU(shell.get(),
true);
510 auto flush_awaiting_tasks = [&](Dart_NativeArguments
args) {
512 task_runners.GetIOTaskRunner()->PostTask([io_manager] {
514 std::shared_ptr<impeller::Context> impeller_context =
515 io_manager->GetImpellerContext();
519 impeller_context->StoreTaskForGPU([] {}, [] {});
525 AddNativeCallback(
"FlushGpuAwaitingTasks",
528 ASSERT_TRUE(shell->IsSetup());
530 configuration.SetEntrypoint(
"toByteDataWithoutGPU");
532 shell->RunEngine(std::move(configuration), [&](
auto result) {
536 message_latch.
Wait();
537 DestroyShell(std::move(shell), task_runners);
540TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImage16Float) {
541 sk_sp<MockDlImage>
image(
new MockDlImage());
542 EXPECT_CALL(*
image, GetSize)
543 .WillRepeatedly(Return(
DlISize(100, 100)));
546 auto texture = std::make_shared<MockTexture>(desc);
547 EXPECT_CALL(*
image, impeller_texture).WillOnce(Return(
texture));
548 std::vector<uint8_t>
buffer;
549 buffer.reserve(100 * 100 * 8);
550 auto context = MakeConvertDlImageToSkImageContext(buffer);
551 bool did_call =
false;
552 MockSnapshotDelegate snapshot_delegate;
553 EXPECT_CALL(snapshot_delegate, MakeRenderContextCurrent)
554 .WillRepeatedly(Return(
true));
559 ASSERT_TRUE(
image.ok());
560 ASSERT_TRUE(
image.value());
561 EXPECT_EQ(100,
image.value()->width());
562 EXPECT_EQ(100,
image.value()->height());
563 EXPECT_EQ(kRGBA_F16_SkColorType,
image.value()->colorType());
564 EXPECT_EQ(
nullptr,
image.value()->colorSpace());
566 snapshot_delegate.GetWeakPtr(), context);
567 EXPECT_TRUE(did_call);
570TEST(ImageEncodingImpellerTest, ConvertDlImageToSkImage10XR) {
571 sk_sp<MockDlImage>
image(
new MockDlImage());
572 EXPECT_CALL(*
image, GetSize)
573 .WillRepeatedly(Return(
DlISize(100, 100)));
576 auto texture = std::make_shared<MockTexture>(desc);
577 EXPECT_CALL(*
image, impeller_texture).WillOnce(Return(
texture));
578 std::vector<uint8_t>
buffer;
579 buffer.reserve(100 * 100 * 4);
580 auto context = MakeConvertDlImageToSkImageContext(buffer);
581 bool did_call =
false;
582 MockSnapshotDelegate snapshot_delegate;
583 EXPECT_CALL(snapshot_delegate, MakeRenderContextCurrent)
584 .WillRepeatedly(Return(
true));
589 ASSERT_TRUE(
image.ok());
590 ASSERT_TRUE(
image.value());
591 EXPECT_EQ(100,
image.value()->width());
592 EXPECT_EQ(100,
image.value()->height());
593 EXPECT_EQ(kBGR_101010x_XR_SkColorType,
image.value()->colorType());
594 EXPECT_EQ(
nullptr,
image.value()->colorSpace());
596 snapshot_delegate.GetWeakPtr(), context);
597 EXPECT_TRUE(did_call);
600TEST(ImageEncodingImpellerTest, PngEncoding10XR) {
603 SkImageInfo info = SkImageInfo::Make(
604 width,
height, kBGR_101010x_XR_SkColorType, kUnpremul_SkAlphaType);
606 auto surface = SkSurfaces::Raster(info);
607 SkCanvas* canvas =
surface->getCanvas();
610 paint.setColor(SK_ColorBLUE);
611 paint.setAntiAlias(
true);
613 canvas->clear(SK_ColorWHITE);
614 canvas->drawCircle(
width / 2,
height / 2, 100, paint);
619 EXPECT_TRUE(
png.ok());
623struct PngMemoryReader {
629void PngMemoryRead(png_structp png_ptr,
631 png_size_t byte_count_to_read) {
632 PngMemoryReader* memory_reader =
633 reinterpret_cast<PngMemoryReader*
>(png_get_io_ptr(png_ptr));
634 if (memory_reader->offset + byte_count_to_read > memory_reader->size) {
635 png_error(png_ptr,
"Read error in PngMemoryRead");
637 memcpy(out_bytes, memory_reader->data + memory_reader->offset,
639 memory_reader->offset += byte_count_to_read;
645 png_create_read_struct(PNG_LIBPNG_VER_STRING,
nullptr,
nullptr,
nullptr);
650 png_infop info = png_create_info_struct(png);
652 png_destroy_read_struct(&png,
nullptr,
nullptr);
657 [&png, &info]() { png_destroy_read_struct(&png, &info,
nullptr); });
659 if (setjmp(png_jmpbuf(png))) {
663 PngMemoryReader memory_reader = {
664 .data = png_data, .offset = 0, .size = png_size};
665 png_set_read_fn(png, &memory_reader, PngMemoryRead);
667 png_read_info(png, info);
669 int width = png_get_image_width(png, info);
670 int height = png_get_image_height(png, info);
671 png_byte
color_type = png_get_color_type(png, info);
672 png_byte bit_depth = png_get_bit_depth(png, info);
674 if (bit_depth == 16) {
675 png_set_strip_16(png);
678 png_set_palette_to_rgb(png);
681 png_read_update_info(png, info);
683 std::vector<png_bytep> row_pointers;
684 row_pointers.reserve(
height);
687 row_pointers.push_back(
688 reinterpret_cast<png_bytep
>(result.data() +
i *
width));
691 png_read_image(png, row_pointers.data());
697TEST(ImageEncodingImpellerTest, PngEncodingBGRA10XR) {
700 SkImageInfo info = SkImageInfo::Make(
701 width,
height, kBGRA_10101010_XR_SkColorType, kUnpremul_SkAlphaType);
703 auto surface = SkSurfaces::Raster(info);
704 SkCanvas* canvas =
surface->getCanvas();
707 paint.setColor(SK_ColorBLUE);
708 paint.setAntiAlias(
true);
710 canvas->clear(SK_ColorRED);
711 canvas->drawCircle(
width / 2,
height / 2, 25, paint);
716 ASSERT_TRUE(
png.ok());
718 ReadPngFromMemory(
png.value()->bytes(),
png.value()->size());
719 ASSERT_TRUE(pixels.
ok());
720 EXPECT_EQ(pixels.
value()[0], 0xff0000ff);
721 int middle = 100 * 50 + 50;
722 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...
virtual bool MakeRenderContextCurrent()=0
virtual void MakeRasterSnapshot(sk_sp< DisplayList > display_list, DlISize picture_size, std::function< void(sk_sp< DlImage >)> callback)=0
virtual std::shared_ptr< TextureRegistry > GetTextureRegistry()=0
Gets the registry of external textures currently in use by the rasterizer. These textures may be upda...
virtual sk_sp< DlImage > MakeRasterSnapshotSync(sk_sp< DisplayList > display_list, DlISize picture_size)=0
virtual sk_sp< SkImage > ConvertToRasterImage(sk_sp< SkImage > image)=0
virtual GrDirectContext * GetGrContext()=0
virtual std::unique_ptr< GpuImageResult > MakeSkiaGpuImage(sk_sp< DisplayList > display_list, const SkImageInfo &image_info)=0
Attempts to create a GrBackendTexture for the specified DisplayList. May result in a raster bitmap if...
virtual void CacheRuntimeStage(const std::shared_ptr< impeller::RuntimeStage > &runtime_stage)=0
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
fml::WeakPtr< IOManager > GetIOManager() const
static UIDartState * Current()
MOCK_METHOD(void, CacheRuntimeStage,(const std::shared_ptr< impeller::RuntimeStage > &),(override))
MOCK_METHOD(bool, MakeRenderContextCurrent,(),(override))
MOCK_METHOD(std::shared_ptr< TextureRegistry >, GetTextureRegistry,(),(override))
MOCK_METHOD(GrDirectContext *, GetGrContext,(),(override))
MOCK_METHOD(std::unique_ptr< GpuImageResult >, MakeSkiaGpuImage,(sk_sp< DisplayList >, const SkImageInfo &),(override))
MOCK_METHOD(void, MakeRasterSnapshot,(sk_sp< DisplayList >, DlISize, std::function< void(sk_sp< DlImage >)>),(override))
MOCK_METHOD(sk_sp< SkImage >, ConvertToRasterImage,(sk_sp< SkImage >),(override))
MOCK_METHOD(sk_sp< DlImage >, MakeRasterSnapshotSync,(sk_sp< DisplayList >, DlISize),(override))
fml::TaskRunnerAffineWeakPtr< SnapshotDelegate > GetWeakPtr()
MOCK_METHOD(void, Execute,(const Handlers &handlers),(const))
MOCK_METHOD(void, SetSwitch,(bool value))
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
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)
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)
std::shared_ptr< const fml::Mapping > data