5#define FML_USED_ON_EMBEDDER
28#include "third_party/abseil-cpp/absl/base/no_destructor.h"
29#include "third_party/dart/runtime/include/bin/dart_io_api.h"
30#include "third_party/dart/runtime/include/dart_api.h"
31#include "third_party/skia/include/core/SkSurface.h"
34#define ALLOW_IMPELLER (IMPELLER_SUPPORTS_RENDERING && IMPELLER_ENABLE_VULKAN)
37#include <vulkan/vulkan.h>
39#include "impeller/entity/vk/entity_shaders_vk.h"
40#include "impeller/entity/vk/framebuffer_blend_shaders_vk.h"
41#include "impeller/entity/vk/modern_shaders_vk.h"
45#include "impeller/renderer/vk/compute_shaders_vk.h"
48static std::vector<std::shared_ptr<fml::Mapping>> ShaderLibraryMappings() {
50 std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_vk_data,
51 impeller_entity_shaders_vk_length),
52 std::make_shared<fml::NonOwnedMapping>(impeller_modern_shaders_vk_data,
53 impeller_modern_shaders_vk_length),
54 std::make_shared<fml::NonOwnedMapping>(
55 impeller_framebuffer_blend_shaders_vk_data,
56 impeller_framebuffer_blend_shaders_vk_length),
57 std::make_shared<fml::NonOwnedMapping>(
58 impeller_compute_shaders_vk_data, impeller_compute_shaders_vk_length),
65 std::shared_ptr<impeller::ContextVK> context;
66 std::shared_ptr<impeller::SurfaceContextVK> surface_context;
71bool ImpellerVulkanContextHolder::Initialize(
bool enable_validation) {
82 if (!context || !context->IsValid()) {
87 impeller::vk::SurfaceKHR vk_surface;
88 impeller::vk::HeadlessSurfaceCreateInfoEXT surface_create_info;
89 auto res = context->GetInstance().createHeadlessSurfaceEXT(
94 if (res != impeller::vk::Result::eSuccess) {
96 << impeller::vk::to_string(res);
100 impeller::vk::UniqueSurfaceKHR
surface{vk_surface, context->GetInstance()};
101 surface_context = context->CreateSurfaceContext();
102 if (!surface_context->SetWindowSurface(std::move(surface),
114#if defined(FML_OS_WIN)
115#include <combaseapi.h>
118#if defined(FML_OS_POSIX)
124static absl::NoDestructor<std::unique_ptr<Shell>>
g_shell;
129 auto device_pixel_ratio = 3.0;
130 auto physical_width = 2400.0;
131 auto physical_height = 1800.0;
133 std::vector<std::unique_ptr<Display>>
displays;
134 displays.push_back(std::make_unique<Display>(
135 0, 60, physical_width, physical_height, device_pixel_ratio));
140 metrics.physical_width = physical_width;
141 metrics.physical_height = physical_height;
142 metrics.display_id = 0;
143 metrics.physical_min_width_constraint = physical_width;
144 metrics.physical_max_width_constraint = physical_width;
145 metrics.physical_min_height_constraint = physical_height;
146 metrics.physical_max_height_constraint = physical_height;
152 DlCanvas* GetRootCanvas()
override {
return nullptr; }
155 void CancelFrame()
override {}
158 void BeginFrame(GrDirectContext* context,
160 raster_thread_merger)
override {}
163 void PrepareFlutterView(
DlISize frame_size,
164 double device_pixel_ratio)
override {}
167 void PrerollCompositeEmbeddedView(
169 std::unique_ptr<EmbeddedViewParams>
params)
override {}
183 bool render_to_surface)
196 impeller_context_holder_(
std::move(impeller_context_holder)) {}
200 if (impeller_context_holder_.context) {
201 impeller_context_holder_.context->Shutdown();
209 return std::static_pointer_cast<impeller::Context>(
210 impeller_context_holder_.context);
221 auto surface = std::make_unique<GPUSurfaceVulkanImpeller>(
222 nullptr, impeller_context_holder_.surface_context);
227 auto surface = std::make_unique<TesterGPUSurfaceSoftware>(
235 if (sk_surface_ !=
nullptr &&
236 sk_surface_->width() ==
size.width &&
237 sk_surface_->height() ==
size.height) {
242 SkImageInfo info = SkImageInfo::MakeN32(
243 size.width,
size.height, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
244 sk_surface_ = SkSurfaces::Raster(info,
nullptr);
246 if (sk_surface_ ==
nullptr) {
248 <<
"Could not create backing store for software rendering.";
262 return external_view_embedder_;
266 sk_sp<SkSurface> sk_surface_ =
nullptr;
268 std::shared_ptr<TesterExternalViewEmbedder> external_view_embedder_ =
269 std::make_shared<TesterExternalViewEmbedder>();
281 main_task_runner_(
std::move(main_task_runner)),
282 ui_task_runner_(
std::move(ui_task_runner)),
283 run_forever_(run_forever) {}
309 if (!has_terminated_) {
311 has_terminated_ =
true;
322 bool run_forever_ =
false;
323 std::optional<DartErrorCode> last_error_;
324 bool has_terminated_ =
false;
336#if defined(FML_OS_POSIX)
339 sigaddset(&
set, SIGPROF);
340 pthread_sigmask(SIG_UNBLOCK, &
set, NULL);
346 bool multithreaded) {
347 const auto thread_label =
"io.flutter.test.";
360 std::unique_ptr<ThreadHost> threadhost;
367 threadhost = std::make_unique<ThreadHost>(
370 platform_task_runner = current_task_runner;
371 raster_task_runner = threadhost->raster_thread->GetTaskRunner();
372 ui_task_runner = threadhost->ui_thread->GetTaskRunner();
373 io_task_runner = threadhost->io_thread->GetTaskRunner();
375 platform_task_runner = raster_task_runner = ui_task_runner =
376 io_task_runner = current_task_runner;
380 platform_task_runner,
390 if (!impeller_context_holder.Initialize(
399 impeller_context_holder)](
Shell& shell)
mutable {
400 return std::make_unique<TesterPlatformView>(
401 shell, shell.
GetTaskRunners(), std::move(impeller_context_holder));
405 return std::make_unique<Rasterizer>(
412 on_create_platform_view,
418 if (!shell || !shell->
IsSetup()) {
419 FML_LOG(ERROR) <<
"Could not set up the shell.";
424 FML_LOG(ERROR) <<
"Dart kernel file not specified.";
433 const char* locale_json =
434 "{\"method\":\"setLocale\",\"args\":[\"en\",\"US\",\"\",\"\",\"zh\","
435 "\"CN\",\"\",\"\"]}";
437 locale_json, locale_json + std::strlen(locale_json));
440 std::make_unique<flutter::PlatformMessage>(
441 "flutter/localization", std::move(locale_bytes), response));
443 std::initializer_list<fml::FileMapping::Protection> protection = {
445 auto main_dart_file_mapping = std::make_unique<fml::FileMapping>(
451 auto isolate_configuration =
454 if (!isolate_configuration) {
455 FML_LOG(ERROR) <<
"Could create isolate configuration.";
459 auto asset_manager = std::make_shared<flutter::AssetManager>();
460 asset_manager->PushBack(std::make_unique<flutter::DirectoryAssetBundle>(
462 asset_manager->PushBack(std::make_unique<flutter::DirectoryAssetBundle>(
468 std::move(asset_manager));
480 bool engine_did_run =
false;
483 auto task_observer_add = [&completion_observer]() {
485 reinterpret_cast<intptr_t
>(&completion_observer),
486 [&completion_observer]() { completion_observer.
DidProcessTask(); });
489 auto task_observer_remove = [&completion_observer, &latch]() {
491 reinterpret_cast<intptr_t
>(&completion_observer));
495 shell->
RunEngine(std::move(run_configuration),
496 [&engine_did_run, &ui_task_runner,
499 engine_did_run =
true;
519 if (!engine_did_run) {
529#define EXPORTED __declspec(dllexport)
531#define EXPORTED __attribute__((visibility("default")))
536 std::shared_ptr<fml::FileMapping> mapping =
548 Dart_Handle lib = Dart_LookupLibrary(Dart_NewStringFromCString(uri));
549 if (Dart_IsError(lib)) {
552 return Dart_GetField(lib, Dart_NewStringFromCString(
name));
557 auto isolate = Dart_CurrentIsolate();
558 auto spawn_task = [shell, entrypoint = std::string(entrypoint),
559 route = std::string(route)]() {
561 shell->GetSettings(),
nullptr,
563 configuration.SetEntrypoint(entrypoint);
568 return std::make_unique<TesterPlatformView>(
570 std::move(impeller_context_holder));
574 return std::make_unique<Rasterizer>(
582 ->
Spawn(std::move(configuration), route, on_create_platform_view,
583 on_create_rasterizer)
589 spawned_shell->GetTaskRunners().GetUITaskRunner(), [spawned_shell]() {
590 fml::MessageLoop::GetCurrent().AddTaskObserver(
591 reinterpret_cast<intptr_t>(spawned_shell), [spawned_shell]() {
592 if (spawned_shell->EngineHasLivePorts()) {
596 fml::MessageLoop::GetCurrent().RemoveTaskObserver(
597 reinterpret_cast<intptr_t>(spawned_shell));
599 fml::TaskRunner::RunNowOrPostTask(
600 spawned_shell->GetTaskRunners().GetPlatformTaskRunner(),
601 [spawned_shell]() { delete spawned_shell; });
610 shell->GetTaskRunners().GetPlatformTaskRunner(), spawn_task);
612 Dart_EnterIsolate(isolate);
618 Dart_Handle isolate_lib = Dart_LookupLibrary(
tonic::ToDart(
"dart:isolate"));
620 Dart_Handle isolate_type = Dart_GetNonNullableType(
624 Dart_SetField(isolate_type,
tonic::ToDart(
"_mayExit"), Dart_True());
632 dart::bin::SetExecutableName(
argv[0]);
633 dart::bin::SetExecutableArguments(argc - 1,
argv);
643 if (!command_line.positional_args().empty()) {
646 settings.application_kernel_asset = command_line.positional_args()[0];
649 if (settings.application_kernel_asset.empty()) {
650 FML_LOG(ERROR) <<
"Dart kernel file not specified.";
654 settings.leak_vm =
false;
655 settings.enable_platform_isolates =
true;
657 if (settings.icu_data_path.empty()) {
658 settings.icu_data_path =
"icudtl.dat";
662 settings.log_tag =
"";
664 settings.log_message_callback = [](
const std::string& tag,
667 std::cout << tag <<
": ";
669 std::cout <<
message << std::endl;
684 settings.unhandled_exception_callback = [](
const std::string&
error,
685 const std::string& stack_trace) {
686 FML_LOG(ERROR) <<
"Unhandled exception" << std::endl
687 <<
"Exception: " <<
error << std::endl
688 <<
"Stack trace: " << stack_trace;
693#if defined(FML_OS_WIN)
694 CoInitializeEx(
nullptr, COINIT_MULTITHREADED);
699 flutter::Switch::RunForever)),
701 flutter::Switch::ForceMultithreading)));
static Dart_Handle LoadLibraryFromKernel(const std::shared_ptr< const fml::Mapping > &mapping)
Developer-facing API for rendering anything within the engine.
RunStatus
Indicates the result of the call to Engine::Run.
Interface implemented by all platform surfaces that can present a software backing store to the "scre...
static std::unique_ptr< IsolateConfiguration > CreateForKernel(std::unique_ptr< const fml::Mapping > kernel)
Creates a JIT isolate configuration using the specified snapshot. This is a convenience method for th...
Specifies all the configuration required by the runtime library to launch the root isolate....
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...
ScriptCompletionTaskObserver(Shell &shell, fml::RefPtr< fml::TaskRunner > main_task_runner, fml::RefPtr< fml::TaskRunner > ui_task_runner, bool run_forever)
int GetExitCodeForLastError() const
std::optional< DartErrorCode > GetUIIsolateLastError() const
Used by embedders to get the last error from the Dart UI Isolate, if one exists.
static std::unique_ptr< Shell > Create(const PlatformData &platform_data, const TaskRunners &task_runners, Settings settings, const CreateCallback< PlatformView > &on_create_platform_view, const CreateCallback< Rasterizer > &on_create_rasterizer, bool is_gpu_disabled=false)
Creates a shell instance using the provided settings. The callbacks to create the various shell subco...
bool EngineHasLivePorts() const
Used by embedders to check if the Engine is running and has any live ports remaining....
void RunEngine(RunConfiguration run_configuration)
Starts an isolate for the given RunConfiguration.
std::unique_ptr< Shell > Spawn(RunConfiguration run_configuration, const std::string &initial_route, const CreateCallback< PlatformView > &on_create_platform_view, const CreateCallback< Rasterizer > &on_create_rasterizer) const
Creates one Shell from another Shell where the created Shell takes the opportunity to share any inter...
bool EngineHasPendingMicrotasks() const
Used by embedders to check if the Engine is running and has any microtasks that have been queued but ...
void OnDisplayUpdates(std::vector< std::unique_ptr< Display > > displays)
Notifies the display manager of the updates.
const TaskRunners & GetTaskRunners() const override
If callers wish to interact directly with any shell subcomponents, they must (on the platform thread)...
std::function< std::unique_ptr< T >(Shell &)> CreateCallback
bool IsSetup() const
Used by embedders to check if all shell subcomponents are initialized. It is the embedder's responsib...
fml::WeakPtr< PlatformView > GetPlatformView()
Platform views may only be accessed on the platform task runner.
bool EnableRasterCache() const override
TesterGPUSurfaceSoftware(GPUSurfaceSoftwareDelegate *delegate, bool render_to_surface)
static std::unique_ptr< FileMapping > CreateReadOnly(const std::string &path)
static MallocMapping Copy(const T *begin, const T *end)
void RemoveTaskObserver(intptr_t key)
static void EnsureInitializedForCurrentThread()
void AddTaskObserver(intptr_t key, const fml::closure &callback)
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
static TaskQueueId GetCurrentTaskQueueId()
static MessageLoopTaskQueues * GetInstance()
void AddTaskObserver(TaskQueueId queue_id, intptr_t key, const fml::closure &callback)
void RemoveTaskObserver(TaskQueueId queue_id, intptr_t key)
static void RunNowOrPostTask(const fml::RefPtr< fml::TaskRunner > &runner, const fml::closure &task)
virtual void PostTask(const fml::closure &task) override
static std::shared_ptr< ContextVK > Create(Settings settings)
const EmbeddedViewParams * params
G_BEGIN_DECLS GBytes * message
const uint8_t uint32_t uint32_t GError ** error
G_BEGIN_DECLS FlutterViewId view_id
FlutterDesktopBinaryReply callback
#define FML_LOG(severity)
#define FML_CHECK(condition)
#define FML_DCHECK(condition)
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
static void UnblockSIGPROF()
EXPORTED Dart_Handle LookupEntryPoint(const char *uri, const char *name)
@ NoError
No error has occurred.
int RunTester(const flutter::Settings &settings, bool run_forever, bool multithreaded)
void PrintUsage(const std::string &executable_name)
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 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
DEF_SWITCHES_START aot vmservice shared library name
constexpr FlutterViewId kImplicitViewId
EXPORTED void ForceShutdownIsolate()
static void ConfigureShell(Shell *shell)
static absl::NoDestructor< std::unique_ptr< Shell > > g_shell
Settings SettingsFromCommandLine(const fml::CommandLine &command_line, bool require_merged_platform_ui_thread)
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 set
EXPORTED void Spawn(const char *entrypoint, const char *route)
EXPORTED Dart_Handle LoadLibraryFromKernel(const char *path)
const std::string_view FlagForSwitch(Switch swtch)
std::string AbsolutePath(const std::string &path)
fml::UniqueFD GetCachesDirectory()
fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor)
fml::UniqueFD OpenDirectory(const char *path, bool create_if_necessary, FilePermission permission)
internal::CopyableLambda< T > MakeCopyable(T lambda)
std::function< void()> closure
CommandLine CommandLineFromPlatformOrArgcArgv(int argc, const char *const *argv)
fml::UniqueFD OpenFile(const char *path, bool create_if_necessary, FilePermission permission)
This can open a directory on POSIX, but not on Windows.
void Initialize(zx::channel directory_request, std::optional< zx::eventpair > view_ref)
Initializes Dart bindings for the Fuchsia application model.
Dart_Handle ToDart(const T &object)
bool CheckAndHandleError(Dart_Handle handle)
std::string application_kernel_asset
fml::UniqueFD::element_type assets_dir
bool enable_vulkan_validation
double device_pixel_ratio
std::vector< std::shared_ptr< fml::Mapping > > shader_libraries_data
PFN_vkGetInstanceProcAddr proc_address_callback
fml::UniqueFD cache_directory
int main(int argc, char *argv[])