diff --git a/engine/src/flutter/shell/platform/embedder/embedder.cc b/engine/src/flutter/shell/platform/embedder/embedder.cc index f55e52c895..0ab8a3a870 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.cc +++ b/engine/src/flutter/shell/platform/embedder/embedder.cc @@ -16,6 +16,7 @@ #include "flutter/fml/closure.h" #include "flutter/fml/make_copyable.h" #include "flutter/fml/native_library.h" +#include "flutter/fml/thread.h" #include "third_party/dart/runtime/bin/elf_loader.h" #include "third_party/dart/runtime/include/dart_native_api.h" @@ -1450,10 +1451,33 @@ FlutterEngineResult FlutterEngineInitialize(size_t version, } } #endif - + auto custom_task_runners = SAFE_ACCESS(args, custom_task_runners, nullptr); + auto thread_config_callback = [&custom_task_runners]( + const fml::Thread::ThreadConfig& config) { + fml::Thread::SetCurrentThreadName(config); + if (!custom_task_runners || !custom_task_runners->thread_priority_setter) { + return; + } + FlutterThreadPriority priority = FlutterThreadPriority::kNormal; + switch (config.priority) { + case fml::Thread::ThreadPriority::BACKGROUND: + priority = FlutterThreadPriority::kBackground; + break; + case fml::Thread::ThreadPriority::NORMAL: + priority = FlutterThreadPriority::kNormal; + break; + case fml::Thread::ThreadPriority::DISPLAY: + priority = FlutterThreadPriority::kDisplay; + break; + case fml::Thread::ThreadPriority::RASTER: + priority = FlutterThreadPriority::kRaster; + break; + } + custom_task_runners->thread_priority_setter(priority); + }; auto thread_host = flutter::EmbedderThreadHost::CreateEmbedderOrEngineManagedThreadHost( - SAFE_ACCESS(args, custom_task_runners, nullptr)); + custom_task_runners, thread_config_callback); if (!thread_host || !thread_host->IsValid()) { return LOG_EMBEDDER_ERROR(kInvalidArguments, diff --git a/engine/src/flutter/shell/platform/embedder/embedder.h b/engine/src/flutter/shell/platform/embedder/embedder.h index d20f939796..4cefaab892 100644 --- a/engine/src/flutter/shell/platform/embedder/embedder.h +++ b/engine/src/flutter/shell/platform/embedder/embedder.h @@ -226,6 +226,18 @@ typedef enum { kFlutterTextDirectionLTR = 2, } FlutterTextDirection; +/// Valid values for priority of Thread. +typedef enum { + /// Suitable for threads that shouldn't disrupt high priority work. + kBackground = 0, + /// Default priority level. + kNormal = 1, + /// Suitable for threads which generate data for the display. + kDisplay = 2, + /// Suitable for thread which raster data. + kRaster = 3, +} FlutterThreadPriority; + typedef struct _FlutterEngine* FLUTTER_API_SYMBOL(FlutterEngine); typedef struct { @@ -1061,6 +1073,9 @@ typedef struct { /// and platform task runners. This makes the Flutter engine use the same /// thread for both task runners. const FlutterTaskRunnerDescription* render_task_runner; + /// Specify a callback that is used to set the thread priority for embedder + /// task runners. + void (*thread_priority_setter)(FlutterThreadPriority); } FlutterCustomTaskRunners; typedef struct { diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc index a36a87503d..4d0d41160d 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc @@ -261,6 +261,8 @@ bool FlutterWindowsEngine::RunWithEntrypoint(const char* entrypoint) { FlutterCustomTaskRunners custom_task_runners = {}; custom_task_runners.struct_size = sizeof(FlutterCustomTaskRunners); custom_task_runners.platform_task_runner = &platform_task_runner; + custom_task_runners.thread_priority_setter = + &WindowsPlatformThreadPrioritySetter; FlutterProjectArgs args = {}; args.struct_size = sizeof(FlutterProjectArgs); diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.h b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.h index ccc915e08b..07030c748a 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.h +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.h @@ -32,6 +32,32 @@ namespace flutter { class FlutterWindowsView; +// Update the thread priority for the Windows engine. +static void WindowsPlatformThreadPrioritySetter( + FlutterThreadPriority priority) { + // TODO(99502): Add support for tracing to the windows embedding so we can + // mark thread priorities and success/failure. + switch (priority) { + case FlutterThreadPriority::kBackground: { + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); + break; + } + case FlutterThreadPriority::kDisplay: { + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); + break; + } + case FlutterThreadPriority::kRaster: { + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); + break; + } + case FlutterThreadPriority::kNormal: { + // For normal or default priority we do not need to set the priority + // class. + break; + } + } +} + // Manages state associated with the underlying FlutterEngine that isn't // related to its display. // @@ -163,9 +189,7 @@ class FlutterWindowsEngine { void UpdateSemanticsEnabled(bool enabled); // Returns true if the semantics tree is enabled. - bool semantics_enabled() const { - return semantics_enabled_; - } + bool semantics_enabled() const { return semantics_enabled_; } // Returns the native accessibility node with the given id. gfx::NativeViewAccessible GetNativeAccessibleFromId(AccessibilityNodeId id); diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_engine_unittests.cc b/engine/src/flutter/shell/platform/windows/flutter_windows_engine_unittests.cc index 1218cf8fbb..2fd0b8b722 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_engine_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_engine_unittests.cc @@ -66,9 +66,14 @@ TEST(FlutterWindowsEngine, RunDoesExpectedInitialization) { EXPECT_EQ(strcmp(args->dart_entrypoint_argv[1], "arg2"), 0); EXPECT_NE(args->platform_message_callback, nullptr); EXPECT_NE(args->custom_task_runners, nullptr); + EXPECT_NE(args->custom_task_runners->thread_priority_setter, nullptr); EXPECT_EQ(args->custom_dart_entrypoint, nullptr); EXPECT_NE(args->vsync_callback, nullptr); + args->custom_task_runners->thread_priority_setter( + FlutterThreadPriority::kRaster); + EXPECT_EQ(GetThreadPriority(GetCurrentThread()), + THREAD_PRIORITY_ABOVE_NORMAL); return kSuccess; })); @@ -318,6 +323,27 @@ TEST(FlutterWindowsEngine, DispatchSemanticsAction) { EXPECT_TRUE(called); } +TEST(FlutterWindowsEngine, SetsThreadPriority) { + WindowsPlatformThreadPrioritySetter(FlutterThreadPriority::kBackground); + EXPECT_EQ(GetThreadPriority(GetCurrentThread()), + THREAD_PRIORITY_BELOW_NORMAL); + + WindowsPlatformThreadPrioritySetter(FlutterThreadPriority::kDisplay); + EXPECT_EQ(GetThreadPriority(GetCurrentThread()), + THREAD_PRIORITY_ABOVE_NORMAL); + + WindowsPlatformThreadPrioritySetter(FlutterThreadPriority::kRaster); + EXPECT_EQ(GetThreadPriority(GetCurrentThread()), + THREAD_PRIORITY_ABOVE_NORMAL); + + // FlutterThreadPriority::kNormal does not change thread priority, reset to 0 + // here. + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); + + WindowsPlatformThreadPrioritySetter(FlutterThreadPriority::kNormal); + EXPECT_EQ(GetThreadPriority(GetCurrentThread()), THREAD_PRIORITY_NORMAL); +} + TEST(FlutterWindowsEngine, AddPluginRegistrarDestructionCallback) { std::unique_ptr engine = GetTestEngine(); EngineModifier modifier(engine.get());