浏览代码

add more code...

/siyaoH-1.17-PlatformMessage
Kevin Gu 4 年前
当前提交
ab9d2afd
共有 100 个文件被更改,包括 7081 次插入1206 次删除
  1. 16
      com.unity.uiwidgets/Runtime/ui2/compositing.cs
  2. 21
      com.unity.uiwidgets/Runtime/ui2/hooks.cs
  3. 2
      com.unity.uiwidgets/Runtime/ui2/native_bindings.cs
  4. 43
      com.unity.uiwidgets/Runtime/ui2/painting.cs
  5. 93
      engine/Build.bee.cs
  6. 7
      engine/src/common/settings.h
  7. 10
      engine/src/engine.cc
  8. 14
      engine/src/flow/skia_gpu_object.cc
  9. 2
      engine/src/flow/skia_gpu_object.h
  10. 2
      engine/src/lib/ui/compositing/scene.cc
  11. 35
      engine/src/lib/ui/compositing/scene_builder.cc
  12. 2
      engine/src/lib/ui/compositing/scene_builder.h
  13. 49
      engine/src/lib/ui/painting/gradient.cc
  14. 7
      engine/src/lib/ui/painting/image_decoder.cc
  15. 13
      engine/src/lib/ui/painting/image_decoder.h
  16. 10
      engine/src/lib/ui/window/window.cc
  17. 2
      engine/src/lib/ui/window/window.h
  18. 62
      engine/src/runtime/mono_api.cc
  19. 4
      engine/src/runtime/mono_api.h
  20. 108
      engine/src/runtime/runtime_controller.cc
  21. 30
      engine/src/runtime/runtime_controller.h
  22. 2
      engine/src/runtime/runtime_delegate.h
  23. 8
      engine/src/shell/common/animator.cc
  24. 229
      engine/src/shell/common/engine.cc
  25. 15
      engine/src/shell/common/engine.h
  26. 622
      engine/src/shell/common/shell.cc
  27. 335
      engine/src/shell/common/shell.h
  28. 2
      engine/src/shell/common/vsync_waiter.h
  29. 3
      com.unity.uiwidgets/Runtime/engine2.meta
  30. 7
      engine/src/runtime/start_up.cc
  31. 9
      engine/src/runtime/start_up.h
  32. 194
      engine/src/shell/common/canvas_spy.cc
  33. 165
      engine/src/shell/common/canvas_spy.h
  34. 64
      engine/src/shell/common/run_configuration.cc
  35. 42
      engine/src/shell/common/run_configuration.h
  36. 24
      engine/third_party/Unity/IUnityUIWidgets.h
  37. 154
      com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs
  38. 3
      com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs.meta
  39. 48
      engine/src/assets/asset_manager.cc
  40. 35
      engine/src/assets/asset_manager.h
  41. 26
      engine/src/assets/asset_resolver.h
  42. 41
      engine/src/assets/directory_asset_bundle.cc
  43. 30
      engine/src/assets/directory_asset_bundle.h
  44. 14
      engine/src/shell/gpu/gpu_surface_delegate.h
  45. 328
      engine/src/shell/gpu/gpu_surface_gl.cc
  46. 68
      engine/src/shell/gpu/gpu_surface_gl.h
  47. 100
      engine/src/shell/gpu/gpu_surface_gl_delegate.cc
  48. 65
      engine/src/shell/gpu/gpu_surface_gl_delegate.h
  49. 90
      engine/src/shell/gpu/gpu_surface_software.cc
  50. 44
      engine/src/shell/gpu/gpu_surface_software.h
  51. 11
      engine/src/shell/gpu/gpu_surface_software_delegate.cc
  52. 22
      engine/src/shell/gpu/gpu_surface_software_delegate.h
  53. 1001
      engine/src/shell/platform/embedder/embedder.cc
  54. 459
      engine/src/shell/platform/embedder/embedder.h
  55. 252
      engine/src/shell/platform/embedder/embedder_engine.cc
  56. 84
      engine/src/shell/platform/embedder/embedder_engine.h
  57. 47
      engine/src/shell/platform/embedder/embedder_external_texture_gl.cc
  58. 43
      engine/src/shell/platform/embedder/embedder_external_texture_gl.h
  59. 98
      engine/src/shell/platform/embedder/embedder_external_view.cc
  60. 118
      engine/src/shell/platform/embedder/embedder_external_view.h
  61. 265
      engine/src/shell/platform/embedder/embedder_external_view_embedder.cc
  62. 77
      engine/src/shell/platform/embedder/embedder_external_view_embedder.h
  63. 205
      engine/src/shell/platform/embedder/embedder_layers.cc
  64. 46
      engine/src/shell/platform/embedder/embedder_layers.h
  65. 32
      engine/src/shell/platform/embedder/embedder_platform_message_response.cc
  66. 31
      engine/src/shell/platform/embedder/embedder_platform_message_response.h
  67. 35
      engine/src/shell/platform/embedder/embedder_render_target.cc
  68. 30
      engine/src/shell/platform/embedder/embedder_render_target.h
  69. 69
      engine/src/shell/platform/embedder/embedder_render_target_cache.cc
  70. 49
      engine/src/shell/platform/embedder/embedder_render_target_cache.h
  71. 9
      engine/src/shell/platform/embedder/embedder_surface.cc
  72. 25
      engine/src/shell/platform/embedder/embedder_surface.h
  73. 107
      engine/src/shell/platform/embedder/embedder_surface_gl.cc
  74. 73
      engine/src/shell/platform/embedder/embedder_surface_gl.h
  75. 110
      engine/src/shell/platform/embedder/embedder_surface_software.cc
  76. 51
      engine/src/shell/platform/embedder/embedder_surface_software.h
  77. 82
      engine/src/shell/platform/embedder/embedder_task_runner.cc
  78. 51
      engine/src/shell/platform/embedder/embedder_task_runner.h
  79. 206
      engine/src/shell/platform/embedder/embedder_thread_host.cc
  80. 40
      engine/src/shell/platform/embedder/embedder_thread_host.h
  81. 74
      engine/src/shell/platform/embedder/platform_view_embedder.cc
  82. 62
      engine/src/shell/platform/embedder/platform_view_embedder.h
  83. 39
      engine/src/shell/platform/embedder/vsync_waiter_embedder.cc
  84. 28
      engine/src/shell/platform/embedder/vsync_waiter_embedder.h
  85. 43
      engine/src/shell/platform/unity/gfx_worker_task_runner.cc
  86. 43
      engine/src/shell/platform/unity/gfx_worker_task_runner.h
  87. 281
      engine/src/shell/platform/unity/uiwidgets_panel.cc
  88. 55
      engine/src/shell/platform/unity/uiwidgets_panel.h
  89. 95
      engine/src/shell/platform/unity/uiwidgets_system.cc
  90. 69
      engine/src/shell/platform/unity/uiwidgets_system.h
  91. 231
      engine/src/shell/platform/unity/unity_surface_manager.cc
  92. 51
      engine/src/shell/platform/unity/unity_surface_manager.h
  93. 116
      engine/src/shell/platform/unity/win32_task_runner.cc
  94. 73
      engine/src/shell/platform/unity/win32_task_runner.h

16
com.unity.uiwidgets/Runtime/ui2/compositing.cs


using AOT;
using RSG;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.ui2 {
public class Scene : NativeWrapperDisposable {

D.assert(() => {
if (_layerStack.isNotEmpty()) {
_EngineLayerWrapper currentLayer = _layerStack.last();
currentLayer._debugChildren ??= new List<_EngineLayerWrapper>();
currentLayer._debugChildren = currentLayer._debugChildren ?? new List<_EngineLayerWrapper>();
currentLayer._debugChildren.Add(newLayer);
}

_EngineLayerWrapper wrapper = retainedLayer as _EngineLayerWrapper;
SceneBuilder_addRetained(_ptr, wrapper._ptr);
}
public void addPicture(
Offset offset,
Picture picture,
bool isComplexHint = false,
bool willChangeHint = false
) {
int hints = (isComplexHint ? 1 : 0) | (willChangeHint ? 2 : 0);
SceneBuilder_addPicture(_ptr, offset.dx, offset.dy, picture._ptr, hints);
}
[DllImport(NativeBindings.dllName)]
static extern IntPtr SceneBuilder_constructor();

[DllImport(NativeBindings.dllName)]
static extern IntPtr SceneBuilder_build(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern IntPtr SceneBuilder_addPicture(IntPtr ptr, float dx, float dy, IntPtr picture, int hints);
[DllImport(NativeBindings.dllName)]
static extern void SceneBuilder_addRetained(IntPtr ptr, IntPtr retainedLayer);
}

21
com.unity.uiwidgets/Runtime/ui2/hooks.cs


namespace Unity.UIWidgets.ui2 {
public static class Hooks {
public static void hook() {
#if UNITY_EDITOR
[UnityEditor.InitializeOnLoadMethod]
#else
[RuntimeInitializeOnLoadMethod]
#endif
static void hook() {
Mono_throwException,
Mono_timelineGetMicros);
Mono_throwException);
Window_hook(
Window_constructor,

throw new Exception(Marshal.PtrToStringAnsi(exception));
}
delegate long Mono_TimelineGetMicrosCallback();
[MonoPInvokeCallback(typeof(Mono_TimelineGetMicrosCallback))]
static long Mono_timelineGetMicros() {
return Environment.TickCount * 1000L;
}
static extern void Mono_hook(Mono_ThrowExceptionCallback throwException,
Mono_TimelineGetMicrosCallback timelineGetMicros);
static extern void Mono_hook(Mono_ThrowExceptionCallback throwException);
delegate IntPtr Window_constructorCallback(IntPtr ptr);

2
com.unity.uiwidgets/Runtime/ui2/native_bindings.cs


}
protected NativeWrapperDisposable(IntPtr ptr) {
D.assert(_ptr != IntPtr.Zero);
D.assert(ptr != IntPtr.Zero);
_ptr = ptr;
}

43
com.unity.uiwidgets/Runtime/ui2/painting.cs


}
}
else {
_objects ??= new object[_kObjectCount];
_objectPtrs ??= new IntPtr[_kObjectCount];
_objects = _objects ?? new object[_kObjectCount];
_objectPtrs = _objectPtrs ?? new IntPtr[_kObjectCount];
_objects[_kShaderIndex] = value;
_objectPtrs[_kShaderIndex] = value._ptr;

}
}
else {
_objects ??= new object[_kObjectCount];
_objectPtrs ??= new IntPtr[_kObjectCount];
_objects = _objects ?? new object[_kObjectCount];
_objectPtrs = _objectPtrs ?? new IntPtr[_kObjectCount];
if (((_ColorFilter) _objects[_kColorFilterIndex])?.creator != value) {
_objects[_kColorFilterIndex] = nativeFilter;

}
}
else {
_objects ??= new object[_kObjectCount];
_objectPtrs ??= new IntPtr[_kObjectCount];
_objects = _objects ?? new object[_kObjectCount];
_objectPtrs = _objectPtrs ?? new IntPtr[_kObjectCount];
if (((_ImageFilter) _objects[_kImageFilterIndex])?.creator != value) {
_objects[_kImageFilterIndex] = nativeFilter;

float rotation = 0.0f,
bool largeArc = false,
bool clockwise = true) {
radius ??= Radius.zero;
radius = radius ?? Radius.zero;
D.assert(PaintingUtils._offsetIsValid(arcEnd));
D.assert(PaintingUtils._radiusIsValid(radius));

float rotation = 0.0f,
bool largeArc = false,
bool clockwise = true) {
radius ??= Radius.zero;
radius = radius ?? Radius.zero;
D.assert(PaintingUtils._offsetIsValid(arcEndDelta));
D.assert(PaintingUtils._radiusIsValid(radius));

internal const int _kTypeBlur = 0;
internal const int _kTypeMatrix = 1;
internal _ImageFilter _toNativeImageFilter() => _nativeFilter ??= _makeNativeImageFilter();
internal _ImageFilter _toNativeImageFilter() => _nativeFilter = _nativeFilter ?? _makeNativeImageFilter();
_ImageFilter _makeNativeImageFilter() {
if (_data == null) {

var colorsArray = PaintingUtils._encodeColorList(colors);
var colorStopsArray = colorStops?.ToArray() ?? new float[] { };
fixed (float* endPointsBuffer = &endPointsArray[0])
fixed (uint* colorsBuffer = &colorsArray[0])
fixed (float* colorStopsBuffer = &colorStopsArray[0])
fixed (float* matrix4Buffer = &matrix4[0]) {
fixed (float* endPointsBuffer = endPointsArray)
fixed (uint* colorsBuffer = colorsArray)
fixed (float* colorStopsBuffer = colorStopsArray)
fixed (float* matrix4Buffer = matrix4) {
var gradient = new Gradient(Gradient_constructor());
Gradient_initLinear(
gradient._ptr, endPointsBuffer, endPointsArray.Length,

var colorsArray = PaintingUtils._encodeColorList(colors);
var colorStopsArray = colorStops?.ToArray() ?? new float[] { };
fixed (uint* colorsBuffer = &colorsArray[0])
fixed (float* colorStopsBuffer = &colorStopsArray[0])
fixed (float* matrix4Buffer = &matrix4[0]) {
fixed (uint* colorsBuffer = colorsArray)
fixed (float* colorStopsBuffer = colorStopsArray)
fixed (float* matrix4Buffer = matrix4) {
var gradient = new Gradient(Gradient_constructor());
if (focal == null || (focal == center && focalRadius == 0.0f)) {

var colorsArray = PaintingUtils._encodeColorList(colors);
var colorStopsArray = colorStops?.ToArray() ?? new float[] { };
fixed (uint* colorsBuffer = &colorsArray[0])
fixed (float* colorStopsBuffer = &colorStopsArray[0])
fixed (float* matrix4Buffer = &matrix4[0]) {
fixed (uint* colorsBuffer = colorsArray)
fixed (float* colorStopsBuffer = colorStopsArray)
fixed (float* matrix4Buffer = matrix4) {
var gradient = new Gradient(Gradient_constructor());
Gradient_initSweep(gradient._ptr,
center.dx, center.dy,

throw new ArgumentException("\"matrix4\" must have 16 entries.");
}
fixed (float* matrix4Buffer = &matrix4[0]) {
fixed (float* matrix4Buffer = matrix4) {
ImageShader_initWithImage(_ptr, image._ptr, (int) tmx, (int) tmy, matrix4Buffer);
}
}

throw new ArgumentException("\"recorder\" must not already be associated with another Canvas.");
}
cullRect ??= Rect.largest;
cullRect = cullRect ?? Rect.largest;
_ptr = Canvas_constructor(recorder._ptr, cullRect.left, cullRect.top,
cullRect.right,
cullRect.bottom);

public void drawColor(Color color, BlendMode blendMode) {
D.assert(color != null);
D.assert(blendMode != null);
Canvas_drawColor(_ptr, color.value, (int) blendMode);
}

93
engine/Build.bee.cs


{
Sources =
{
"src/assets/asset_manager.cc",
"src/assets/asset_manager.h",
"src/assets/asset_resolver.h",
"src/assets/directory_asset_bundle.cc",
"src/assets/directory_asset_bundle.h",
"src/common/settings.cc",
"src/common/settings.h",
"src/common/task_runners.cc",

"src/runtime/mono_microtask_queue.h",
"src/runtime/mono_state.cc",
"src/runtime/mono_state.h",
//"src/runtime/runtime_controller.cc",
//"src/runtime/runtime_controller.h",
"src/runtime/runtime_controller.cc",
"src/runtime/runtime_controller.h",
"src/runtime/start_up.cc",
"src/runtime/start_up.h",
//"src/shell/common/engine.cc",
//"src/shell/common/engine.h",
"src/shell/common/canvas_spy.cc",
"src/shell/common/canvas_spy.h",
"src/shell/common/engine.cc",
"src/shell/common/engine.h",
"src/shell/common/persistent_cache.cc",
"src/shell/common/persistent_cache.h",
"src/shell/common/pipeline.cc",

"src/shell/common/pointer_data_dispatcher.h",
"src/shell/common/rasterizer.cc",
"src/shell/common/rasterizer.h",
//"src/shell/common/shell.cc",
//"src/shell/common/shell.h",
"src/shell/common/run_configuration.cc",
"src/shell/common/run_configuration.h",
"src/shell/common/shell.cc",
"src/shell/common/shell.h",
"src/shell/common/shell_io_manager.cc",
"src/shell/common/shell_io_manager.h",
"src/shell/common/surface.cc",

"src/shell/common/vsync_waiter_fallback.cc",
"src/shell/common/vsync_waiter_fallback.h",
"src/shell/gpu/gpu_surface_delegate.h",
"src/shell/gpu/gpu_surface_gl.cc",
"src/shell/gpu/gpu_surface_gl.h",
"src/shell/gpu/gpu_surface_gl_delegate.cc",
"src/shell/gpu/gpu_surface_gl_delegate.h",
"src/shell/gpu/gpu_surface_software.cc",
"src/shell/gpu/gpu_surface_software.h",
"src/shell/gpu/gpu_surface_software_delegate.cc",
"src/shell/gpu/gpu_surface_software_delegate.h",
"src/shell/platform/embedder/embedder.cc",
"src/shell/platform/embedder/embedder.h",
"src/shell/platform/embedder/embedder_engine.cc",
"src/shell/platform/embedder/embedder_engine.h",
"src/shell/platform/embedder/embedder_external_texture_gl.cc",
"src/shell/platform/embedder/embedder_external_texture_gl.h",
"src/shell/platform/embedder/embedder_external_view.cc",
"src/shell/platform/embedder/embedder_external_view.h",
"src/shell/platform/embedder/embedder_external_view_embedder.cc",
"src/shell/platform/embedder/embedder_external_view_embedder.h",
"src/shell/platform/embedder/embedder_layers.cc",
"src/shell/platform/embedder/embedder_layers.h",
"src/shell/platform/embedder/embedder_platform_message_response.cc",
"src/shell/platform/embedder/embedder_platform_message_response.h",
"src/shell/platform/embedder/embedder_render_target.cc",
"src/shell/platform/embedder/embedder_render_target.h",
"src/shell/platform/embedder/embedder_render_target_cache.cc",
"src/shell/platform/embedder/embedder_render_target_cache.h",
"src/shell/platform/embedder/embedder_surface.cc",
"src/shell/platform/embedder/embedder_surface.h",
"src/shell/platform/embedder/embedder_surface_gl.cc",
"src/shell/platform/embedder/embedder_surface_gl.h",
"src/shell/platform/embedder/embedder_surface_software.cc",
"src/shell/platform/embedder/embedder_surface_software.h",
"src/shell/platform/embedder/embedder_task_runner.cc",
"src/shell/platform/embedder/embedder_task_runner.h",
"src/shell/platform/embedder/embedder_thread_host.cc",
"src/shell/platform/embedder/embedder_thread_host.h",
"src/shell/platform/embedder/platform_view_embedder.cc",
"src/shell/platform/embedder/platform_view_embedder.h",
"src/shell/platform/embedder/vsync_waiter_embedder.cc",
"src/shell/platform/embedder/vsync_waiter_embedder.h",
"src/shell/platform/unity/gfx_worker_task_runner.cc",
"src/shell/platform/unity/gfx_worker_task_runner.h",
"src/shell/platform/unity/unity_surface_manager.cc",
"src/shell/platform/unity/unity_surface_manager.h",
"src/shell/platform/unity/uiwidgets_panel.cc",
"src/shell/platform/unity/uiwidgets_panel.h",
"src/shell/platform/unity/uiwidgets_system.cc",
"src/shell/platform/unity/uiwidgets_system.h",
"src/shell/platform/unity/win32_task_runner.cc",
"src/shell/platform/unity/win32_task_runner.h",
"src/shell/version/version.cc",
"src/shell/version/version.h",

np.LinkerSettings().Add(l => l.WithCustomFlags_workaround(new[] {"/DEBUG:FULL"}));
SetupFml(np);
SetupRadidJson(np);
SetupSkia(np);
SetupTxt(np);

}
static void SetupRadidJson(NativeProgram np)
{
// gn desc .\out\host_debug_unopt\ //third_party/rapidjson:rapidjson
np.Defines.Add(new[]
{
"RAPIDJSON_HAS_STDSTRING",
"RAPIDJSON_HAS_CXX11_RANGE_FOR",
"RAPIDJSON_HAS_CXX11_RVALUE_REFS",
"RAPIDJSON_HAS_CXX11_TYPETRAITS",
"RAPIDJSON_HAS_CXX11_NOEXCEPT"
});
np.IncludeDirectories.Add(flutterRoot + "/third_party/rapidjson/include");
}
// static void SetupSkiaAndroid(NativeProgram np)
// {

7
engine/src/common/settings.h


using TaskObserverAdd =
std::function<void(intptr_t /* key */, fml::closure /* callback */)>;
using TaskObserverRemove = std::function<void(intptr_t /* key */)>;
using UnhandledExceptionCallback =
std::function<bool(const std::string& /* error */,
const std::string& /* stack trace */)>;
using UnhandledExceptionCallback = std::function<bool(
const std::string& /* error */, const std::string& /* stack trace */)>;
// TODO(chinmaygarde): Deprecate all the "path" struct members in favor of the
// callback that generates the mapping from these paths.

// Engine settings
TaskObserverAdd task_observer_add;
TaskObserverRemove task_observer_remove;
fml::closure mono_entrypoint_callback;
// The main isolate is current when this callback is made. This is a good spot
// to perform native Dart bindings for libraries not built in.
fml::closure root_isolate_create_callback;

10
engine/src/engine.cc


#include <assert.h>
#include "Unity/IUnityGraphics.h"
#include "Unity/IUnityUIWidgets.h"
#include "shell/platform/unity/uiwidgets_system.h"
static IUnityInterfaces* s_UnityInterfaces = NULL;
static IUnityGraphics* s_Graphics = NULL;

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
UnityPluginLoad(IUnityInterfaces* unityInterfaces) {
s_UnityInterfaces = unityInterfaces;
s_Graphics = s_UnityInterfaces->Get<IUnityGraphics>();
s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);
OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
uiwidgets::UIWidgetsSystem::GetInstancePtr()->BindUnityInterfaces(unityInterfaces);
s_Graphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent);
uiwidgets::UIWidgetsSystem::GetInstancePtr()->UnBindUnityInterfaces();
}
// --------------------------------------------------------------------------

14
engine/src/flow/skia_gpu_object.cc


drain_pending_(false),
context_(context) {}
SkiaUnrefQueue::~SkiaUnrefQueue() { FML_DCHECK(objects_.empty()); }
SkiaUnrefQueue::~SkiaUnrefQueue() {
if (!objects_.empty()) {
Drain(false);
}
}
void SkiaUnrefQueue::Unref(SkRefCnt* object) {
std::scoped_lock lock(mutex_);

}
}
void SkiaUnrefQueue::Drain() {
void SkiaUnrefQueue::Drain(bool performDeferredCleanup) {
TRACE_EVENT0("uiwidgets", "SkiaUnrefQueue::Drain");
std::deque<SkRefCnt*> skia_objects;
{

skia_object->unref();
}
if (context_ && skia_objects.size() > 0) {
context_->performDeferredCleanup(std::chrono::milliseconds(0));
if (performDeferredCleanup) {
if (context_ && skia_objects.size() > 0) {
context_->performDeferredCleanup(std::chrono::milliseconds(0));
}
}
}

2
engine/src/flow/skia_gpu_object.h


// to go away), we may need to pre-emptively drain the unref queue. It is the
// responsibility of the caller to ensure that no further unrefs are queued
// after this call.
void Drain();
void Drain(bool performDeferredCleanup = true);
private:
const fml::RefPtr<fml::TaskRunner> task_runner_;

2
engine/src/lib/ui/compositing/scene.cc


return std::move(layer_tree_);
}
UIWIDGETS_API(void) Scene_dispose(Scene* ptr) { ptr->Release(); }
} // namespace uiwidgets

35
engine/src/lib/ui/compositing/scene_builder.cc


SceneBuilder::~SceneBuilder() = default;
fml::RefPtr<EngineLayer> SceneBuilder::pushTransform(float* matrix4) {
fml::RefPtr<EngineLayer> SceneBuilder::pushTransform(const float* matrix4) {
SkMatrix sk_matrix = ToSkMatrix(matrix4);
auto layer = std::make_shared<TransformLayer>(sk_matrix);
PushLayer(layer);

if (layer_stack_.size() > 1) {
layer_stack_.pop_back();
}
}
UIWIDGETS_API(SceneBuilder*) SceneBuilder_constructor() {
const auto builder = fml::MakeRefCounted<SceneBuilder>();
builder->AddRef();
return builder.get();
}
UIWIDGETS_API(void) SceneBuilder_dispose(SceneBuilder* ptr) { ptr->Release(); }
UIWIDGETS_API(void)
SceneBuilder_pushTransform(SceneBuilder* ptr, const float* matrix4) {
ptr->pushTransform(matrix4);
}
UIWIDGETS_API(void)
SceneBuilder_pushOffset(SceneBuilder* ptr, float dx, float dy) {
ptr->pushOffset(dx, dy);
}
UIWIDGETS_API(void)
SceneBuilder_pop(SceneBuilder* ptr) { ptr->pop(); }
UIWIDGETS_API(Scene*) SceneBuilder_build(SceneBuilder* ptr) {
const auto scene = ptr->build();
scene->AddRef();
return scene.get();
}
UIWIDGETS_API(void)
SceneBuilder_addPicture(SceneBuilder* ptr, float dx, float dy, Picture* picture,
int hints) {
ptr->addPicture(dx, dy, picture, hints);
}
} // namespace uiwidgets

2
engine/src/lib/ui/compositing/scene_builder.h


}
~SceneBuilder();
fml::RefPtr<EngineLayer> pushTransform(float* matrix4);
fml::RefPtr<EngineLayer> pushTransform(const float* matrix4);
fml::RefPtr<EngineLayer> pushOffset(float dx, float dy);
fml::RefPtr<EngineLayer> pushClipRect(float left, float right, float top,

49
engine/src/lib/ui/painting/gradient.cc


CanvasGradient::~CanvasGradient() = default;
UIWIDGETS_API(CanvasGradient*)
Gradient_constructor() {
const auto gradiant = CanvasGradient::Create();
gradiant->AddRef();
return gradiant.get();
}
UIWIDGETS_API(void) Gradient_dispose(CanvasGradient* ptr) { ptr->Release(); }
UIWIDGETS_API(void)
Gradient_initLinear(CanvasGradient* ptr, const float* end_points,
int end_points_length, const int* colors, int colors_length,
const float* color_stops, int color_stops_length,
SkTileMode tile_mode, const float* matrix4) {
ptr->initLinear(end_points, end_points_length, colors, colors_length,
color_stops, color_stops_length, tile_mode, matrix4);
}
UIWIDGETS_API(void)
Gradient_initRadial(CanvasGradient* ptr, float center_x, float center_y,
float radius, const int* colors, int colors_length,
const float* color_stops, int color_stops_length,
SkTileMode tile_mode, const float* matrix4) {
ptr->initRadial(center_x, center_y, radius, colors, colors_length,
color_stops, color_stops_length, tile_mode, matrix4);
}
UIWIDGETS_API(void)
Gradient_initConical(CanvasGradient* ptr, float start_x, float start_y,
float start_radius, float end_x, float end_y,
float end_radius, const int* colors, int colors_length,
const float* color_stops, int color_stops_length,
SkTileMode tile_mode, const float* matrix4) {
ptr->initTwoPointConical(start_x, start_y, start_radius, end_x, end_y,
end_radius, colors, colors_length, color_stops,
color_stops_length, tile_mode, matrix4);
}
UIWIDGETS_API(void)
Gradient_initSweep(CanvasGradient* ptr, float center_x, float center_y,
const int* colors, int colors_length,
const float* color_stops, int color_stops_length,
SkTileMode tile_mode, float start_angle, float end_angle,
const float* matrix4) {
ptr->initSweep(center_x, center_y, colors, colors_length, color_stops,
color_stops_length, tile_mode, start_angle, end_angle,
matrix4);
}
} // namespace uiwidgets

7
engine/src/lib/ui/painting/image_decoder.cc


#include "src/codec/SkCodecImageGenerator.h"
namespace uiwidgets {
ImageDecoder::ImageDecoder(
TaskRunners runners,
std::shared_ptr<fml::ConcurrentTaskRunner> concurrent_task_runner,
fml::WeakPtr<IOManager> io_manager) {}
fml::WeakPtr<ImageDecoder> ImageDecoder::GetWeakPtr() const {
return fml::WeakPtr<ImageDecoder>();
}
} // namespace uiwidgets

13
engine/src/lib/ui/painting/image_decoder.h


#pragma once
#include <flutter/fml/concurrent_message_loop.h>
#include <flutter/fml/memory/weak_ptr.h>
#include "common/task_runners.h"
#include "lib/ui/io_manager.h"
public:
ImageDecoder(
TaskRunners runners,
std::shared_ptr<fml::ConcurrentTaskRunner> concurrent_task_runner,
fml::WeakPtr<IOManager> io_manager);
fml::WeakPtr<ImageDecoder> GetWeakPtr() const;
};
} // namespace uiwidgets

10
engine/src/lib/ui/window/window.cc


typedef Mono_Handle (*Window_constructorCallback)(Window* window);
static Window_constructorCallback Window_constructor_;
Window_constructorCallback Window_constructor_;
static Window_disposeCallback Window_dispose_;
Window_disposeCallback Window_dispose_;
typedef void (*Window_updateWindowMetricsCallback)(
float devicePixelRatio, float width, float height, float depth,

float systemGestureInsetRight, float systemGestureInsetBottom,
float systemGestureInsetLeft);
static Window_updateWindowMetricsCallback Window_updateWindowMetrics_;
Window_updateWindowMetricsCallback Window_updateWindowMetrics_;
static Window_beginFrameCallback Window_beginFrame_;
Window_beginFrameCallback Window_beginFrame_;
static Window_drawFrameCallback Window_drawFrame_;
Window_drawFrameCallback Window_drawFrame_;
UIWIDGETS_API(void)
Window_hook(Window_constructorCallback Window_constructor,

2
engine/src/lib/ui/window/window.h


virtual void ScheduleFrame() = 0;
virtual void Render(Scene* scene) = 0;
virtual void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) = 0;
virtual FontCollection& GetFontCollection() = 0;
// virtual FontCollection& GetFontCollection() = 0;
virtual void SetNeedsReportTimings(bool value) = 0;
protected:

62
engine/src/runtime/mono_api.cc


#include <flutter/fml/logging.h>
#include <flutter/fml/thread_local.h>
#include "mono_isolate.h"
FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<_Mono_Isolate> tls_isolate;
FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<Mono_Isolate> tls_isolate;
return new _Mono_Isolate{isolate_data};
return new _Mono_Isolate(isolate_data);
delete static_cast<MonoState*>(data_);
delete static_cast<std::shared_ptr<MonoIsolate>*>(data_);
Mono_Isolate Mono_CurrentIsolate() { return tls_isolate.get(); }
Mono_Isolate Mono_CurrentIsolate() {
Mono_Isolate* ptr = tls_isolate.get();
if (!ptr) {
return nullptr;
}
return *ptr;
}
FML_DCHECK(tls_isolate.get() == nullptr);
tls_isolate.reset(isolate);
Mono_Isolate* ptr = tls_isolate.get();
FML_DCHECK(ptr == nullptr || *ptr == nullptr);
if (!ptr) {
ptr = new Mono_Isolate();
tls_isolate.reset(ptr);
}
*ptr = isolate;
FML_DCHECK(tls_isolate.get() != nullptr);
tls_isolate.reset(nullptr);
Mono_Isolate* ptr = tls_isolate.get();
FML_DCHECK(ptr != nullptr && *ptr != nullptr);
*ptr = nullptr;
Mono_Isolate current = tls_isolate.get();
Mono_Isolate* ptr = tls_isolate.get();
FML_DCHECK(ptr != nullptr);
const Mono_Isolate current = *ptr;
tls_isolate.reset(nullptr);
*ptr = nullptr;
delete current;
}

Mono_ThrowExceptionCallback_(exception);
}
typedef int64_t (*Mono_TimelineGetMicrosCallback)();
static Mono_TimelineGetMicrosCallback Mono_TimelineGetMicrosCallback_;
int64_t Mono_TimelineGetMicros() {
return fml::TimePoint::Now().ToEpochDelta().ToMicroseconds();
}
int64_t Mono_TimelineGetMicros() { return Mono_TimelineGetMicrosCallback_(); }
void Mono_NotifyIdle(int64_t deadline) {}
Mono_hook(Mono_ThrowExceptionCallback throwException,
Mono_TimelineGetMicrosCallback timelineGetMicros) {
Mono_hook(Mono_ThrowExceptionCallback throwException) {
Mono_TimelineGetMicrosCallback_ = timelineGetMicros;
UIWIDGETS_API(Mono_Isolate)
Isolate_current() { return Mono_CurrentIsolate(); }
UIWIDGETS_API(void)
Isolate_enter(Mono_Isolate isolate) { return Mono_EnterIsolate(isolate); }
UIWIDGETS_API(void)
Isolate_exit() { Mono_ExitIsolate(); }
extern "C" int64_t Dart_TimelineGetMicros() { return uiwidgets::Mono_TimelineGetMicros(); }
extern "C" int64_t Dart_TimelineGetMicros() {
return uiwidgets::Mono_TimelineGetMicros();
}

4
engine/src/runtime/mono_api.h


#define UIWIDGETS_API(RETURN) \
extern "C" UNITY_INTERFACE_EXPORT RETURN UNITY_INTERFACE_API
#define UIWIDGETS_CALLBACK(RETURN) static RETURN UNITY_INTERFACE_API
namespace uiwidgets {
typedef void* Mono_Handle;

void Mono_ThrowException(const char* exception);
int64_t Mono_TimelineGetMicros();
void Mono_NotifyIdle(int64_t deadline);
} // namespace uiwidgets

108
engine/src/runtime/runtime_controller.cc


#include "runtime_controller.h"
#include <utility>
#include "flutter/fml/message_loop.h"
#include "flutter/fml/trace_event.h"
#include "lib/ui/compositing/scene.h"

namespace uiwidgets {
RuntimeController::RuntimeController(
RuntimeDelegate& p_client, Settings& p_settings,
TaskRunners p_task_runners,
fml::WeakPtr<SnapshotDelegate> p_snapshot_delegate,
fml::WeakPtr<IOManager> p_io_manager,
fml::RefPtr<SkiaUnrefQueue> p_unref_queue,
fml::WeakPtr<ImageDecoder> p_image_decoder,
const std::function<void(int64_t)>& idle_notification_callback,
const WindowData& p_window_data,
const fml::closure& p_isolate_create_callback,
const fml::closure& p_isolate_shutdown_callback)
: client_(p_client),
settings_(p_settings),
task_runners_(p_task_runners),
snapshot_delegate_(p_snapshot_delegate),
io_manager_(p_io_manager),
unref_queue_(p_unref_queue),
image_decoder_(p_image_decoder),
idle_notification_callback_(idle_notification_callback),
window_data_(std::move(p_window_data)),
isolate_create_callback_(p_isolate_create_callback),
isolate_shutdown_callback_(p_isolate_shutdown_callback) {
auto strong_root_isolate =
MonoIsolate::CreateRootIsolate(settings_, //
task_runners_, //
std::make_unique<Window>(this), //
snapshot_delegate_, //
io_manager_, //
unref_queue_, //
RuntimeDelegate& client, const Settings& settings, TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager, fml::RefPtr<SkiaUnrefQueue> unref_queue,
fml::WeakPtr<ImageDecoder> image_decoder, const WindowData& window_data)
: client_(client),
settings_(settings),
task_runners_(task_runners),
snapshot_delegate_(std::move(snapshot_delegate)),
io_manager_(std::move(io_manager)),
unref_queue_(std::move(unref_queue)),
image_decoder_(std::move(image_decoder)),
window_data_(window_data) {
auto strong_root_isolate =
MonoIsolate::CreateRootIsolate(settings_, //
task_runners_, //
std::make_unique<Window>(this), //
snapshot_delegate_, //
io_manager_, //
unref_queue_, //
image_decoder_ //
)
.lock();

}
}
bool RuntimeController::IsRootIsolateRunning() const {
//std::shared_ptr<MonoIsolate> root_isolate = root_isolate_.lock();
//if (root_isolate) {
// return root_isolate->GetPhase() == DartIsolate::Phase::Running;
//}
//return false;
return true;
}
return std::unique_ptr<RuntimeController>(new RuntimeController(
client_, //
settings_, //
task_runners_, //
snapshot_delegate_, //
io_manager_, //
unref_queue_, //
image_decoder_, //
idle_notification_callback_, //
window_data_, //
isolate_create_callback_, //
isolate_shutdown_callback_ //
));
return std::make_unique<RuntimeController>(client_, //
settings_, //
task_runners_, //
snapshot_delegate_, //
io_manager_, //
unref_queue_, //
image_decoder_, //
window_data_ //
);
}
bool RuntimeController::FlushRuntimeStateToIsolate() {

}
MonoState::Scope scope(root_isolate);
// Idle notifications being in isolate scope are part of the contract.
if (idle_notification_callback_) {
TRACE_EVENT0("flutter", "EmbedderIdleNotification");
idle_notification_callback_(deadline);
}
return true;
}

TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage",
TRACE_EVENT1("uiwidgets", "RuntimeController::DispatchPlatformMessage",
"mode", "basic");
window->DispatchPlatformMessage(std::move(message));
return true;

bool RuntimeController::DispatchPointerDataPacket(
const PointerDataPacket& packet) {
if (auto* window = GetWindowIfAvailable()) {
TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket",
TRACE_EVENT1("uiwidgets", "RuntimeController::DispatchPointerDataPacket",
"mode", "basic");
window->DispatchPointerDataPacket(packet);
return true;

Window* RuntimeController::GetWindowIfAvailable() {
std::shared_ptr<MonoIsolate> root_isolate = root_isolate_.lock();

}
// |WindowClient|
void RuntimeController::ScheduleFrame() {
client_.ScheduleFrame();
}
void RuntimeController::ScheduleFrame() { client_.ScheduleFrame(); }
// |WindowClient|
void RuntimeController::Render(Scene* scene) {

}
// |WindowClient|
FontCollection& RuntimeController::GetFontCollection() {
// return client_.GetFontCollection();
//return nullptr;
}
// FontCollection& RuntimeController::GetFontCollection() {
// return client_.GetFontCollection();
//}
// |WindowClient|
void RuntimeController::SetNeedsReportTimings(bool value) {

std::weak_ptr<MonoIsolate> RuntimeController::GetRootIsolate() {
return root_isolate_;
}
RuntimeController::Locale::Locale(std::string language_code_,
std::string country_code_,

RuntimeController::Locale::~Locale() = default;
} // namespace flutter
} // namespace uiwidgets

30
engine/src/runtime/runtime_controller.h


class RuntimeController final : public WindowClient {
public:
RuntimeController(
RuntimeDelegate& client,
Settings& settings,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager,
fml::RefPtr<SkiaUnrefQueue> unref_queue,
fml::WeakPtr<ImageDecoder> image_decoder,
const std::function<void(int64_t)>& idle_notification_callback,
const WindowData& window_data,
const fml::closure& isolate_create_callback,
const fml::closure& isolate_shutdown_callback);
RuntimeController(RuntimeDelegate& client, const Settings& settings,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager,
fml::RefPtr<SkiaUnrefQueue> unref_queue,
fml::WeakPtr<ImageDecoder> image_decoder,
const WindowData& window_data);
~RuntimeController() override;

bool NotifyIdle(int64_t deadline);
bool IsRootIsolateRunning() const;
bool DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message);
bool DispatchPointerDataPacket(const PointerDataPacket& packet);

};
RuntimeDelegate& client_;
Settings& settings_;
const Settings& settings_;
std::function<void(int64_t)> idle_notification_callback_;
std::pair<bool, uint32_t> root_isolate_return_code_ = {false, 0};
const fml::closure isolate_create_callback_;
const fml::closure isolate_shutdown_callback_;
std::shared_ptr<const fml::Mapping> persistent_isolate_data_;
Window* GetWindowIfAvailable();

void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) override;
// |WindowClient|
FontCollection& GetFontCollection() override;
// FontCollection& GetFontCollection() override;
// |WindowClient|
void SetNeedsReportTimings(bool value) override;

2
engine/src/runtime/runtime_delegate.h


virtual void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) = 0;
// virtual FontCollection& GetFontCollection() = 0;
//virtual FontCollection& GetFontCollection() = 0;
virtual void SetNeedsReportTimings(bool value) = 0;

8
engine/src/shell/common/animator.cc


return (frame_number_ % 2) ? "even" : "odd";
}
static int64_t FxlToMonoOrEarlier(fml::TimePoint time) {
static int64_t FmlToMonoOrEarlier(fml::TimePoint time) {
fml::TimePoint fxl_now = fml::TimePoint::Now();
return (time - fxl_now).ToMicroseconds() + mono_now;
fml::TimePoint fml_now = fml::TimePoint::Now();
return (time - fml_now).ToMicroseconds() + mono_now;
}
void Animator::BeginFrame(fml::TimePoint frame_start_time,

last_frame_begin_time_ = frame_start_time;
last_frame_target_time_ = frame_target_time;
mono_frame_deadline_ = FxlToMonoOrEarlier(frame_target_time);
mono_frame_deadline_ = FmlToMonoOrEarlier(frame_target_time);
{
TRACE_EVENT2("uiwidgets", "Framework Workload", "mode", "basic", "frame",
FrameParity());

229
engine/src/shell/common/engine.cc


#include "flutter/fml/paths.h"
#include "flutter/fml/trace_event.h"
#include "flutter/fml/unique_fd.h"
//#include "lib/snapshot/snapshot.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkPictureRecorder.h"
#include "rapidjson/document.h"
#include "rapidjson/document.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkPictureRecorder.h"
namespace uiwidgets {

static constexpr char kLocalizationChannel[] = "uiwidgets/localization";
static constexpr char kSettingsChannel[] = "uiwidgets/settings";
static constexpr char kIsolateChannel[] = "uiwidgets/isolate";
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
std::unique_ptr<Animator> animator,
TaskRunners task_runners, const WindowData window_data,
Settings settings, std::unique_ptr<Animator> animator,
concurrent_message_loop_(fml::ConcurrentMessageLoop::Create()),
image_decoder_(task_runners,
vm.GetConcurrentWorkerTaskRunner(),
image_decoder_(task_runners, concurrent_message_loop_->GetTaskRunner(),
io_manager),
task_runners_(std::move(task_runners)),
weak_factory_(this) {

runtime_controller_ = std::make_unique<RuntimeController>(
*this, // runtime delegate
&vm, // VM
std::move(isolate_snapshot), // isolate snapshot
task_runners_, // task runners
*this, // runtime delegate
settings_, // settings
task_runners_, // task runners
std::move(io_manager), // io manager
std::move(unref_queue), // Skia unref queue
image_decoder_.GetWeakPtr(), // image decoder
settings_.advisory_script_uri, // advisory script uri
settings_.advisory_script_entrypoint, // advisory script entrypoint
settings_.idle_notification_callback, // idle notification callback
window_data, // window data
settings_.isolate_create_callback, // isolate create callback
settings_.isolate_shutdown_callback, // isolate shutdown callback
settings_.persistent_isolate_data // persistent isolate data
std::move(io_manager), // io manager
std::move(unref_queue), // Skia unref queue
image_decoder_.GetWeakPtr(), // image decoder
window_data // window data
);
pointer_data_dispatcher_ = dispatcher_maker(*this);

return false;
}
// Using libTXT as the text engine.
font_collection_.RegisterFonts(asset_manager_);
if (settings_.use_test_fonts) {
font_collection_.RegisterTestFonts();
}
//// Using libTXT as the text engine.
// font_collection_.RegisterFonts(asset_manager_);
TRACE_EVENT0("flutter", "Engine::Restart");
TRACE_EVENT0("uiwidgets", "Engine::Restart");
if (!configuration.IsValid()) {
FML_LOG(ERROR) << "Engine run configuration was invalid.";
return false;

UpdateAssetManager(nullptr);
return Run(std::move(configuration)) == Engine::RunStatus::Success;
return Run(std::move(configuration)) == RunStatus::Success;
}
Engine::RunStatus Engine::Run(RunConfiguration configuration) {

}
last_entry_point_ = configuration.GetEntrypoint();
last_entry_point_library_ = configuration.GetEntrypointLibrary();
if (isolate_launch_status == Engine::RunStatus::Failure) {
if (isolate_launch_status == RunStatus::Failure) {
FML_LOG(ERROR) << "Engine not prepare and launch isolate.";
return isolate_launch_status;
} else if (isolate_launch_status ==

std::shared_ptr<DartIsolate> isolate =
runtime_controller_->GetRootIsolate().lock();
bool isolate_running =
isolate && isolate->GetPhase() == DartIsolate::Phase::Running;
if (isolate_running) {
tonic::DartState::Scope scope(isolate.get());
if (settings_.root_isolate_create_callback) {
settings_.root_isolate_create_callback();
}
if (settings_.root_isolate_shutdown_callback) {
isolate->AddIsolateShutdownCallback(
settings_.root_isolate_shutdown_callback);
}
std::string service_id = isolate->GetServiceId();
fml::RefPtr<PlatformMessage> service_id_message =
fml::MakeRefCounted<flutter::PlatformMessage>(
kIsolateChannel,
std::vector<uint8_t>(service_id.begin(), service_id.end()),
nullptr);
HandlePlatformMessage(service_id_message);
}
return isolate_running ? Engine::RunStatus::Success
: Engine::RunStatus::Failure;
return RunStatus::Success;
TRACE_EVENT0("flutter", "Engine::PrepareAndLaunchIsolate");
TRACE_EVENT0("uiwidgets", "Engine::PrepareAndLaunchIsolate");
auto isolate_configuration = configuration.TakeIsolateConfiguration();
std::shared_ptr<DartIsolate> isolate =
std::shared_ptr<MonoIsolate> isolate =
runtime_controller_->GetRootIsolate().lock();
if (!isolate) {

// This can happen on iOS after a plugin shows a native window and returns to
// the Flutter ViewController.
if (isolate->GetPhase() == DartIsolate::Phase::Running) {
FML_DLOG(WARNING) << "Isolate was already running!";
return RunStatus::FailureAlreadyRunning;
}
if (!isolate_configuration->PrepareIsolate(*isolate)) {
FML_LOG(ERROR) << "Could not prepare to run the isolate.";
return RunStatus::Failure;
}
if (configuration.GetEntrypointLibrary().empty()) {
if (!isolate->Run(configuration.GetEntrypoint(),
settings_.dart_entrypoint_args)) {
FML_LOG(ERROR) << "Could not run the isolate.";
return RunStatus::Failure;
}
} else {
if (!isolate->RunFromLibrary(configuration.GetEntrypointLibrary(),
configuration.GetEntrypoint(),
settings_.dart_entrypoint_args)) {
FML_LOG(ERROR) << "Could not run the isolate.";
return RunStatus::Failure;
}
}
MonoState::Scope scope(isolate);
const fml::closure entrypoint_callback =
configuration.GetMonoEntrypointCallback();
entrypoint_callback();
TRACE_EVENT0("flutter", "Engine::BeginFrame");
TRACE_EVENT0("uiwidgets", "Engine::BeginFrame");
TRACE_EVENT0("flutter", "Engine::ReportTimings");
TRACE_EVENT0("uiwidgets", "Engine::ReportTimings");
auto trace_event = std::to_string(deadline - Dart_TimelineGetMicros());
TRACE_EVENT1("flutter", "Engine::NotifyIdle", "deadline_now_delta",
auto trace_event = std::to_string(deadline - Mono_TimelineGetMicros());
TRACE_EVENT1("uiwidgets", "Engine::NotifyIdle", "deadline_now_delta",
std::pair<bool, uint32_t> Engine::GetUIIsolateReturnCode() {
return runtime_controller_->GetRootIsolateReturnCode();
}
Dart_Port Engine::GetUIIsolateMainPort() {
return runtime_controller_->GetMainPort();
}
std::string Engine::GetUIIsolateName() {
return runtime_controller_->GetIsolateName();
}
bool Engine::UIIsolateHasLivePorts() {
return runtime_controller_->HasLivePorts();
}
tonic::DartErrorHandleType Engine::GetUIIsolateLastError() {
return runtime_controller_->GetLastError();
}
void Engine::OnOutputSurfaceCreated() {
have_surface_ = true;
StartAnimatorIfPossible();

viewport_metrics_ = metrics;
runtime_controller_->SetViewportMetrics(viewport_metrics_);
if (animator_) {
if (dimensions_changed)
animator_->SetDimensionChangePending();
if (have_surface_)
ScheduleFrame();
if (dimensions_changed) animator_->SetDimensionChangePending();
if (have_surface_) ScheduleFrame();
if (HandleLifecyclePlatformMessage(message.get()))
return;
if (HandleLifecyclePlatformMessage(message.get())) return;
if (HandleLocalizationPlatformMessage(message.get()))
return;
if (HandleLocalizationPlatformMessage(message.get())) return;
if (runtime_controller_->IsRootIsolateRunning() &&
runtime_controller_->DispatchPlatformMessage(std::move(message))) {
if (runtime_controller_->DispatchPlatformMessage(std::move(message))) {
return;
}

rapidjson::Document document;
document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
if (document.HasParseError() || !document.IsObject())
return false;
if (document.HasParseError() || !document.IsObject()) return false;
if (method->value != "setInitialRoute")
return false;
if (method->value != "setInitialRoute") return false;
auto route = root.FindMember("args");
initial_route_ = std::move(route->value.GetString());
return true;

rapidjson::Document document;
document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
if (document.HasParseError() || !document.IsObject())
return false;
if (document.HasParseError() || !document.IsObject()) return false;
if (method == root.MemberEnd() || method->value != "setLocale")
return false;
if (method == root.MemberEnd() || method->value != "setLocale") return false;
if (args == root.MemberEnd() || !args->value.IsArray())
return false;
if (args == root.MemberEnd() || !args->value.IsArray()) return false;
if (args->value.Size() % strings_per_locale != 0)
return false;
if (args->value.Size() % strings_per_locale != 0) return false;
std::vector<std::string> locale_data;
for (size_t locale_index = 0; locale_index < args->value.Size();
locale_index += strings_per_locale) {

}
void Engine::DispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id) {
TRACE_EVENT0("flutter", "Engine::DispatchPointerDataPacket");
TRACE_FLOW_STEP("flutter", "PointerEvent", trace_flow_id);
std::unique_ptr<PointerDataPacket> packet, uint64_t trace_flow_id) {
TRACE_EVENT0("uiwidgets", "Engine::DispatchPointerDataPacket");
TRACE_FLOW_STEP("uiwidgets", "PointerEvent", trace_flow_id);
void Engine::StopAnimator() {
animator_->Stop();
}
void Engine::StopAnimator() { animator_->Stop(); }
if (activity_running_ && have_surface_)
animator_->Start();
if (activity_running_ && have_surface_) animator_->Start();
}
std::string Engine::DefaultRouteName() {

}
void Engine::Render(std::unique_ptr<uiwidgets::LayerTree> layer_tree) {
if (!layer_tree)
return;
if (!layer_tree) return;
// Ensure frame dimensions are sane.
if (layer_tree->frame_size().isEmpty() ||

animator_->Render(std::move(layer_tree));
}
void Engine::UpdateSemantics(SemanticsNodeUpdates update,
CustomAccessibilityActionUpdates actions) {
delegate_.OnEngineUpdateSemantics(std::move(update), std::move(actions));
}
void Engine::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) {
if (message->channel() == kAssetChannel) {
HandleAssetPlatformMessage(std::move(message));

}
void Engine::UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) {
delegate_.UpdateIsolateDescription(isolate_name, isolate_port);
}
FontCollection& Engine::GetFontCollection() {
return font_collection_;
}
// FontCollection& Engine::GetFontCollection() { return font_collection_; }
void Engine::DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id) {

animator_->ScheduleSecondaryVsyncCallback(callback);
}
std::shared_ptr<fml::ConcurrentMessageLoop> Engine::GetConcurrentMessageLoop() {
return concurrent_message_loop_;
}
void Engine::HandleAssetPlatformMessage(fml::RefPtr<PlatformMessage> message) {
fml::RefPtr<PlatformMessageResponse> response = message->response();
if (!response) {

response->CompleteEmpty();
}
const std::string& Engine::GetLastEntrypoint() const {
return last_entry_point_;
}
const std::string& Engine::GetLastEntrypointLibrary() const {
return last_entry_point_library_;
}
} // namespace flutter
} // namespace uiwidgets

15
engine/src/shell/common/engine.h


#include "lib/ui/painting/image_decoder.h"
#include "lib/ui/snapshot_delegate.h"
//#include "lib/ui/text/font_collection.h"
#include <flutter/fml/concurrent_message_loop.h>
#include "include/core/SkPicture.h"
#include "lib/ui/window/platform_message.h"
#include "lib/ui/window/viewport_metrics.h"

virtual void OnEngineHandlePlatformMessage(
fml::RefPtr<PlatformMessage> message) = 0;
virtual void OnPreEngineRestart() = 0;
virtual void UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) = 0;
virtual void SetNeedsReportTimings(bool needs_reporting) = 0;
};

// |PointerDataDispatcher::Delegate|
void ScheduleSecondaryVsyncCallback(const fml::closure& callback) override;
std::shared_ptr<fml::ConcurrentMessageLoop> GetConcurrentMessageLoop();
Engine::Delegate& delegate_;
Delegate& delegate_;
std::shared_ptr<fml::ConcurrentMessageLoop> concurrent_message_loop_;
std::unique_ptr<Animator> animator_;
std::unique_ptr<RuntimeController> runtime_controller_;

std::unique_ptr<PointerDataDispatcher> pointer_data_dispatcher_;
std::string last_entry_point_;
std::string last_entry_point_library_;
// std::shared_ptr<AssetManager> asset_manager_;
std::shared_ptr<AssetManager> asset_manager_;
FontCollection font_collection_;
// FontCollection font_collection_;
ImageDecoder image_decoder_;
TaskRunners task_runners_;
fml::WeakPtrFactory<Engine> weak_factory_;

622
engine/src/shell/common/shell.cc


// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/common/shell.h"
#include "shell.h"
#include <future>
#include "flutter/assets/directory_asset_bundle.h"
#include "assets/directory_asset_bundle.h"
#include "flutter/fml/icu_util.h"
//#include "flutter/fml/icu_util.h"
#include "flutter/fml/log_settings.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/make_copyable.h"

#include "flutter/fml/unique_fd.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/runtime/start_up.h"
#include "flutter/shell/common/engine.h"
#include "flutter/shell/common/persistent_cache.h"
#include "flutter/shell/common/skia_event_tracer_impl.h"
#include "flutter/shell/common/switches.h"
#include "flutter/shell/common/vsync_waiter.h"
#include "include/core/SkGraphics.h"
#include "include/utils/SkBase64.h"
#include "third_party/dart/runtime/include/dart_tools_api.h"
#include "third_party/skia/include/core/SkGraphics.h"
#include "third_party/skia/include/utils/SkBase64.h"
#include "third_party/tonic/common/log.h"
#include "runtime/start_up.h"
#include "shell/common/engine.h"
#include "shell/common/persistent_cache.h"
//#include "shell/common/skia_event_tracer_impl.h"
//#include "shell/common/switches.h"
#include "shell/common/vsync_waiter.h"
namespace flutter {
namespace uiwidgets {
constexpr char kSkiaChannel[] = "flutter/skia";
constexpr char kSystemChannel[] = "flutter/system";
constexpr char kSkiaChannel[] = "uiwidgets/skia";
constexpr char kSystemChannel[] = "uiwidgets/system";
DartVMRef vm,
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
TaskRunners task_runners, const WindowData window_data, Settings settings,
const Shell::CreateCallback<PlatformView>& on_create_platform_view,
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer) {
if (!task_runners.IsValid()) {

auto shell =
std::unique_ptr<Shell>(new Shell(std::move(vm), task_runners, settings));
auto shell = std::unique_ptr<Shell>(new Shell(task_runners, settings));
// Create the rasterizer on the raster thread.
std::promise<std::unique_ptr<Rasterizer>> rasterizer_promise;

on_create_rasterizer, //
shell = shell.get() //
]() {
TRACE_EVENT0("flutter", "ShellSetupGPUSubsystem");
TRACE_EVENT0("uiwidgets", "ShellSetupGPUSubsystem");
std::unique_ptr<Rasterizer> rasterizer(on_create_rasterizer(*shell));
snapshot_delegate_promise.set_value(rasterizer->GetSnapshotDelegate());
rasterizer_promise.set_value(std::move(rasterizer));

auto platform_view = on_create_platform_view(*shell.get());
if (!platform_view || !platform_view->GetWeakPtr()) {
snapshot_delegate_future.get();
rasterizer_future.get();
return nullptr;
}

if (!vsync_waiter) {
snapshot_delegate_future.get();
rasterizer_future.get();
return nullptr;
}

io_task_runner, //
is_backgrounded_sync_switch = shell->GetIsGpuDisabledSyncSwitch() //
]() {
TRACE_EVENT0("flutter", "ShellSetupIOSubsystem");
TRACE_EVENT0("uiwidgets", "ShellSetupIOSubsystem");
auto io_manager = std::make_unique<ShellIOManager>(
platform_view.getUnsafe()->CreateResourceContext(),
is_backgrounded_sync_switch, io_task_runner);

auto engine_future = engine_promise.get_future();
fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetUITaskRunner(),
fml::MakeCopyable([&engine_promise, //
shell = shell.get(), //
&dispatcher_maker, //
&window_data, //
isolate_snapshot = std::move(isolate_snapshot), //
vsync_waiter = std::move(vsync_waiter), //
&weak_io_manager_future, //
&snapshot_delegate_future, //
&unref_queue_future //
fml::MakeCopyable([&engine_promise, //
shell = shell.get(), //
&dispatcher_maker, //
&window_data, //
vsync_waiter = std::move(vsync_waiter), //
&weak_io_manager_future, //
&snapshot_delegate_future, //
&unref_queue_future //
TRACE_EVENT0("flutter", "ShellSetupUISubsystem");
TRACE_EVENT0("uiwidgets", "ShellSetupUISubsystem");
const auto& task_runners = shell->GetTaskRunners();
// The animator is owned by the UI thread but it gets its vsync pulses

engine_promise.set_value(std::make_unique<Engine>(
*shell, //
dispatcher_maker, //
*shell->GetDartVM(), //
std::move(isolate_snapshot), //
task_runners, //
window_data, //
shell->GetSettings(), //

static void RecordStartupTimestamp() {
if (engine_main_enter_ts == 0) {
engine_main_enter_ts = Dart_TimelineGetMicros();
engine_main_enter_ts = Mono_TimelineGetMicros();
std::vector<std::string>* results,
char delimiter) {
std::vector<std::string>* results, char delimiter) {
std::istringstream ss(input);
std::string token;
while (std::getline(ss, token, delimiter)) {

std::call_once(gShellSettingsInitialization, [&settings] {
RecordStartupTimestamp();
tonic::SetLogHandler(
[](const char* message) { FML_LOG(ERROR) << message; });
InitSkiaEventTracer(settings.trace_skia);
// InitSkiaEventTracer(settings.trace_skia);
}
if (!settings.trace_whitelist.empty()) {

}
if (settings.icu_initialization_required) {
if (settings.icu_data_path.size() != 0) {
fml::icu::InitializeICU(settings.icu_data_path);
} else if (settings.icu_mapper) {
fml::icu::InitializeICUFromMapping(settings.icu_mapper());
} else {
FML_DLOG(WARNING) << "Skipping ICU initialization in the shell.";
}
// if (settings.icu_data_path.size() != 0) {
// fml::icu::InitializeICU(settings.icu_data_path);
//} else if (settings.icu_mapper) {
// fml::icu::InitializeICUFromMapping(settings.icu_mapper());
//} else {
// FML_DLOG(WARNING) << "Skipping ICU initialization in the shell.";
//}
TaskRunners task_runners,
Settings settings,
TaskRunners task_runners, Settings settings,
const Shell::CreateCallback<PlatformView>& on_create_platform_view,
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer) {
return Shell::Create(std::move(task_runners), //

}
std::unique_ptr<Shell> Shell::Create(
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
PerformInitializationTasks(settings);
PersistentCache::SetCacheSkSL(settings.cache_sksl);
TRACE_EVENT0("flutter", "Shell::Create");
auto vm = DartVMRef::Create(settings);
FML_CHECK(vm) << "Must be able to initialize the VM.";
auto vm_data = vm->GetVMData();
return Shell::Create(std::move(task_runners), //
std::move(window_data), //
std::move(settings), //
vm_data->GetIsolateSnapshot(), // isolate snapshot
on_create_platform_view, //
on_create_rasterizer, //
std::move(vm) //
);
}
std::unique_ptr<Shell> Shell::Create(
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
TaskRunners task_runners, const WindowData window_data, Settings settings,
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer,
DartVMRef vm) {
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer) {
TRACE_EVENT0("flutter", "Shell::CreateWithSnapshots");
TRACE_EVENT0("uiwidgets", "Shell::CreateWithSnapshots");
if (!task_runners.IsValid() || !on_create_platform_view ||
!on_create_rasterizer) {

std::unique_ptr<Shell> shell;
fml::TaskRunner::RunNowOrPostTask(
task_runners.GetPlatformTaskRunner(),
fml::MakeCopyable([&latch, //
vm = std::move(vm), //
&shell, //
task_runners = std::move(task_runners), //
window_data, //
settings, //
isolate_snapshot = std::move(isolate_snapshot), //
on_create_platform_view, //
on_create_rasterizer //
fml::MakeCopyable([&latch, //
&shell, //
task_runners = std::move(task_runners), //
window_data, //
settings, //
on_create_platform_view, //
on_create_rasterizer //
shell = CreateShellOnPlatformThread(std::move(vm),
std::move(task_runners), //
window_data, //
settings, //
std::move(isolate_snapshot), //
on_create_platform_view, //
on_create_rasterizer //
shell = CreateShellOnPlatformThread(std::move(task_runners), //
window_data, //
settings, //
on_create_platform_view, //
on_create_rasterizer //
);
latch.Signal();
}));

Shell::Shell(DartVMRef vm, TaskRunners task_runners, Settings settings)
Shell::Shell(TaskRunners task_runners, Settings settings)
vm_(std::move(vm)),
FML_CHECK(vm_) << "Must have access to VM to create a shell.";
FML_DCHECK(task_runners_.IsValid());
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

this->weak_factory_gpu_ =
std::make_unique<fml::WeakPtrFactory<Shell>>(this);
}));
// Install service protocol handlers.
service_protocol_handlers_[ServiceProtocol::kScreenshotExtensionName] = {
task_runners_.GetRasterTaskRunner(),
std::bind(&Shell::OnServiceProtocolScreenshot, this,
std::placeholders::_1, std::placeholders::_2)};
service_protocol_handlers_[ServiceProtocol::kScreenshotSkpExtensionName] = {
task_runners_.GetRasterTaskRunner(),
std::bind(&Shell::OnServiceProtocolScreenshotSKP, this,
std::placeholders::_1, std::placeholders::_2)};
service_protocol_handlers_[ServiceProtocol::kRunInViewExtensionName] = {
task_runners_.GetUITaskRunner(),
std::bind(&Shell::OnServiceProtocolRunInView, this, std::placeholders::_1,
std::placeholders::_2)};
service_protocol_handlers_
[ServiceProtocol::kFlushUIThreadTasksExtensionName] = {
task_runners_.GetUITaskRunner(),
std::bind(&Shell::OnServiceProtocolFlushUIThreadTasks, this,
std::placeholders::_1, std::placeholders::_2)};
service_protocol_handlers_
[ServiceProtocol::kSetAssetBundlePathExtensionName] = {
task_runners_.GetUITaskRunner(),
std::bind(&Shell::OnServiceProtocolSetAssetBundlePath, this,
std::placeholders::_1, std::placeholders::_2)};
service_protocol_handlers_
[ServiceProtocol::kGetDisplayRefreshRateExtensionName] = {
task_runners_.GetUITaskRunner(),
std::bind(&Shell::OnServiceProtocolGetDisplayRefreshRate, this,
std::placeholders::_1, std::placeholders::_2)};
service_protocol_handlers_[ServiceProtocol::kGetSkSLsExtensionName] = {
task_runners_.GetIOTaskRunner(),
std::bind(&Shell::OnServiceProtocolGetSkSLs, this, std::placeholders::_1,
std::placeholders::_2)};
vm_->GetServiceProtocol()->RemoveHandler(this);
fml::AutoResetWaitableEvent ui_latch, gpu_latch, platform_latch, io_latch;

// Since a valid shell will not be returned to the embedder without a valid
// DartVMRef, we can be certain that this is a safe spot to assume a VM is
// running.
::Dart_NotifyLowMemory();
// ::Dart_NotifyLowMemory();
task_runners_.GetRasterTaskRunner()->PostTask(
[rasterizer = rasterizer_->GetWeakPtr()]() {

return;
}
auto run_result = weak_engine->Run(std::move(run_configuration));
if (run_result == flutter::Engine::RunStatus::Failure) {
if (run_result == Engine::RunStatus::Failure) {
FML_LOG(ERROR) << "Could not launch engine with configuration.";
}
result(run_result);

std::optional<DartErrorCode> Shell::GetUIIsolateLastError() const {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
if (!weak_engine_) {
return std::nullopt;
}
switch (weak_engine_->GetUIIsolateLastError()) {
case tonic::kCompilationErrorType:
return DartErrorCode::CompilationError;
case tonic::kApiErrorType:
return DartErrorCode::ApiError;
case tonic::kUnknownErrorType:
return DartErrorCode::UnknownError;
case tonic::kNoError:
return DartErrorCode::NoError;
}
return DartErrorCode::UnknownError;
}
bool Shell::EngineHasLivePorts() const {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
if (!weak_engine_) {
return false;
}
return weak_engine_->UIIsolateHasLivePorts();
}
bool Shell::IsSetup() const {
return is_setup_;
}
bool Shell::IsSetup() const { return is_setup_; }
bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
std::unique_ptr<Engine> engine,

is_setup_ = true;
vm_->GetServiceProtocol()->AddHandler(this, GetServiceProtocolDescription());
PersistentCache::GetCacheForProcess()->AddWorkerTaskRunner(
task_runners_.GetIOTaskRunner());

return true;
}
const Settings& Shell::GetSettings() const {
return settings_;
}
const Settings& Shell::GetSettings() const { return settings_; }
const TaskRunners& Shell::GetTaskRunners() const {
return task_runners_;
}
const TaskRunners& Shell::GetTaskRunners() const { return task_runners_; }
fml::WeakPtr<Rasterizer> Shell::GetRasterizer() const {
FML_DCHECK(is_setup_);

return weak_platform_view_;
}
DartVM* Shell::GetDartVM() {
return &vm_;
}
TRACE_EVENT0("flutter", "Shell::OnPlatformViewCreated");
TRACE_EVENT0("uiwidgets", "Shell::OnPlatformViewCreated");
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

// a synchronous fashion.
fml::AutoResetWaitableEvent latch;
auto raster_task =
fml::MakeCopyable([& waiting_for_first_frame = waiting_for_first_frame_,
fml::MakeCopyable([&waiting_for_first_frame = waiting_for_first_frame_,
rasterizer = rasterizer_->GetWeakPtr(), //
surface = std::move(surface), //
&latch]() mutable {

FML_DCHECK(platform_view);
bool should_post_ui_task =
task_runners_.GetUITaskRunner() != task_runners_.GetPlatformTaskRunner();
ui_task_runner = task_runners_.GetUITaskRunner(), ui_task] {
ui_task_runner = task_runners_.GetUITaskRunner(), ui_task,
should_post_ui_task, &latch] {
fml::TaskRunner::RunNowOrPostTask(ui_task_runner, ui_task);
if (should_post_ui_task) {
fml::TaskRunner::RunNowOrPostTask(ui_task_runner, ui_task);
} else {
latch.Signal();
}
if (!should_post_ui_task) {
ui_task();
latch.Wait();
}
latch.Wait();
TRACE_EVENT0("flutter", "Shell::OnPlatformViewDestroyed");
TRACE_EVENT0("uiwidgets", "Shell::OnPlatformViewDestroyed");
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

// |PlatformView::Delegate|
void Shell::OnPlatformViewDispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet) {
TRACE_EVENT0("flutter", "Shell::OnPlatformViewDispatchPointerDataPacket");
TRACE_FLOW_BEGIN("flutter", "PointerEvent", next_pointer_flow_id_);
TRACE_EVENT0("uiwidgets", "Shell::OnPlatformViewDispatchPointerDataPacket");
TRACE_FLOW_BEGIN("uiwidgets", "PointerEvent", next_pointer_flow_id_);
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
task_runners_.GetUITaskRunner()->PostTask(

}
// |PlatformView::Delegate|
void Shell::OnPlatformViewDispatchSemanticsAction(int32_t id,
SemanticsAction action,
std::vector<uint8_t> args) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
task_runners_.GetUITaskRunner()->PostTask(
[engine = engine_->GetWeakPtr(), id, action, args = std::move(args)] {
if (engine) {
engine->DispatchSemanticsAction(id, action, std::move(args));
}
});
}
// |PlatformView::Delegate|
void Shell::OnPlatformViewSetSemanticsEnabled(bool enabled) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
task_runners_.GetUITaskRunner()->PostTask(
[engine = engine_->GetWeakPtr(), enabled] {
if (engine) {
engine->SetSemanticsEnabled(enabled);
}
});
}
// |PlatformView::Delegate|
void Shell::OnPlatformViewSetAccessibilityFeatures(int32_t flags) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

}
// |PlatformView::Delegate|
void Shell::OnPlatformViewRegisterTexture(
std::shared_ptr<flutter::Texture> texture) {
void Shell::OnPlatformViewRegisterTexture(std::shared_ptr<Texture> texture) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

}
// |Animator::Delegate|
void Shell::OnAnimatorDraw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline) {
void Shell::OnAnimatorDraw(fml::RefPtr<Pipeline<LayerTree>> pipeline) {
[& waiting_for_first_frame = waiting_for_first_frame_,
[&waiting_for_first_frame = waiting_for_first_frame_,
&waiting_for_first_frame_condition = waiting_for_first_frame_condition_,
rasterizer = rasterizer_->GetWeakPtr(),
pipeline = std::move(pipeline)]() {

}
// |Engine::Delegate|
void Shell::OnEngineUpdateSemantics(SemanticsNodeUpdates update,
CustomAccessibilityActionUpdates actions) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
task_runners_.GetPlatformTaskRunner()->PostTask(
[view = platform_view_->GetWeakPtr(), update = std::move(update),
actions = std::move(actions)] {
if (view) {
view->UpdateSemantics(std::move(update), std::move(actions));
}
});
}
// |Engine::Delegate|
void Shell::OnEngineHandlePlatformMessage(
fml::RefPtr<PlatformMessage> message) {
FML_DCHECK(is_setup_);

rapidjson::Document document;
document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
if (document.HasParseError() || !document.IsObject())
return;
if (document.HasParseError() || !document.IsObject()) return;
if (method->value != "Skia.setResourceCacheMaxBytes")
return;
if (method->value != "Skia.setResourceCacheMaxBytes") return;
if (args == root.MemberEnd() || !args->value.IsInt())
return;
if (args == root.MemberEnd() || !args->value.IsInt()) return;
task_runners_.GetRasterTaskRunner()->PostTask(
[rasterizer = rasterizer_->GetWeakPtr(), max_bytes = args->value.GetInt(),

latch.Wait();
}
// |Engine::Delegate|
void Shell::UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) {
Handler::Description description(isolate_port, isolate_name);
vm_->GetServiceProtocol()->SetHandlerDescription(this, description);
}
void Shell::SetNeedsReportTimings(bool value) {
needs_report_timings_ = value;
}
void Shell::SetNeedsReportTimings(bool value) { needs_report_timings_ = value; }
void Shell::ReportTimings() {
FML_DCHECK(is_setup_);

first_frame_rasterized_ = true;
ReportTimings();
} else if (!frame_timings_report_scheduled_) {
#if FLUTTER_RELEASE
#if UIWIDGETS_RELEASE
constexpr int kBatchTimeInMilliseconds = 1000;
#else
constexpr int kBatchTimeInMilliseconds = 100;

}
}
// |ServiceProtocol::Handler|
fml::RefPtr<fml::TaskRunner> Shell::GetServiceProtocolHandlerTaskRunner(
std::string_view method) const {
FML_DCHECK(is_setup_);
auto found = service_protocol_handlers_.find(method);
if (found != service_protocol_handlers_.end()) {
return found->second.first;
}
return task_runners_.GetUITaskRunner();
}
// |ServiceProtocol::Handler|
bool Shell::HandleServiceProtocolMessage(
std::string_view method, // one if the extension names specified above.
const ServiceProtocolMap& params,
rapidjson::Document& response) {
auto found = service_protocol_handlers_.find(method);
if (found != service_protocol_handlers_.end()) {
return found->second.second(params, response);
}
return false;
}
// |ServiceProtocol::Handler|
ServiceProtocol::Handler::Description Shell::GetServiceProtocolDescription()
const {
return {
engine_->GetUIIsolateMainPort(),
engine_->GetUIIsolateName(),
};
}
static void ServiceProtocolParameterError(rapidjson::Document& response,
std::string error_details) {
auto& allocator = response.GetAllocator();
response.SetObject();
const int64_t kInvalidParams = -32602;
response.AddMember("code", kInvalidParams, allocator);
response.AddMember("message", "Invalid params", allocator);
{
rapidjson::Value details(rapidjson::kObjectType);
details.AddMember("details", error_details, allocator);
response.AddMember("data", details, allocator);
}
}
static void ServiceProtocolFailureError(rapidjson::Document& response,
std::string message) {
auto& allocator = response.GetAllocator();
response.SetObject();
const int64_t kJsonServerError = -32000;
response.AddMember("code", kJsonServerError, allocator);
response.AddMember("message", message, allocator);
}
// Service protocol handler
bool Shell::OnServiceProtocolScreenshot(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread());
auto screenshot = rasterizer_->ScreenshotLastLayerTree(
Rasterizer::ScreenshotType::CompressedImage, true);
if (screenshot.data) {
response.SetObject();
auto& allocator = response.GetAllocator();
response.AddMember("type", "Screenshot", allocator);
rapidjson::Value image;
image.SetString(static_cast<const char*>(screenshot.data->data()),
screenshot.data->size(), allocator);
response.AddMember("screenshot", image, allocator);
return true;
}
ServiceProtocolFailureError(response, "Could not capture image screenshot.");
return false;
}
// Service protocol handler
bool Shell::OnServiceProtocolScreenshotSKP(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread());
auto screenshot = rasterizer_->ScreenshotLastLayerTree(
Rasterizer::ScreenshotType::SkiaPicture, true);
if (screenshot.data) {
response.SetObject();
auto& allocator = response.GetAllocator();
response.AddMember("type", "ScreenshotSkp", allocator);
rapidjson::Value skp;
skp.SetString(static_cast<const char*>(screenshot.data->data()),
screenshot.data->size(), allocator);
response.AddMember("skp", skp, allocator);
return true;
}
ServiceProtocolFailureError(response, "Could not capture SKP screenshot.");
return false;
}
// Service protocol handler
bool Shell::OnServiceProtocolRunInView(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
if (params.count("mainScript") == 0) {
ServiceProtocolParameterError(response,
"'mainScript' parameter is missing.");
return false;
}
if (params.count("assetDirectory") == 0) {
ServiceProtocolParameterError(response,
"'assetDirectory' parameter is missing.");
return false;
}
std::string main_script_path =
fml::paths::FromURI(params.at("mainScript").data());
std::string asset_directory_path =
fml::paths::FromURI(params.at("assetDirectory").data());
auto main_script_file_mapping =
std::make_unique<fml::FileMapping>(fml::OpenFile(
main_script_path.c_str(), false, fml::FilePermission::kRead));
auto isolate_configuration = IsolateConfiguration::CreateForKernel(
std::move(main_script_file_mapping));
RunConfiguration configuration(std::move(isolate_configuration));
configuration.SetEntrypointAndLibrary(engine_->GetLastEntrypoint(),
engine_->GetLastEntrypointLibrary());
configuration.AddAssetResolver(
std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory(
asset_directory_path.c_str(), false, fml::FilePermission::kRead)));
auto& allocator = response.GetAllocator();
response.SetObject();
if (engine_->Restart(std::move(configuration))) {
response.AddMember("type", "Success", allocator);
auto new_description = GetServiceProtocolDescription();
rapidjson::Value view(rapidjson::kObjectType);
new_description.Write(this, view, allocator);
response.AddMember("view", view, allocator);
return true;
} else {
FML_DLOG(ERROR) << "Could not run configuration in engine.";
ServiceProtocolFailureError(response,
"Could not run configuration in engine.");
return false;
}
FML_DCHECK(false);
return false;
}
// Service protocol handler
bool Shell::OnServiceProtocolFlushUIThreadTasks(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
// This API should not be invoked by production code.
// It can potentially starve the service isolate if the main isolate pauses
// at a breakpoint or is in an infinite loop.
//
// It should be invoked from the VM Service and and blocks it until UI thread
// tasks are processed.
response.SetObject();
response.AddMember("type", "Success", response.GetAllocator());
return true;
}
bool Shell::OnServiceProtocolGetDisplayRefreshRate(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
response.SetObject();
response.AddMember("type", "DisplayRefreshRate", response.GetAllocator());
response.AddMember("fps", engine_->GetDisplayRefreshRate(),
response.GetAllocator());
return true;
}
bool Shell::OnServiceProtocolGetSkSLs(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetIOTaskRunner()->RunsTasksOnCurrentThread());
response.SetObject();
response.AddMember("type", "GetSkSLs", response.GetAllocator());
rapidjson::Value shaders_json(rapidjson::kObjectType);
PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess();
std::vector<PersistentCache::SkSLCache> sksls = persistent_cache->LoadSkSLs();
for (const auto& sksl : sksls) {
size_t b64_size =
SkBase64::Encode(sksl.second->data(), sksl.second->size(), nullptr);
sk_sp<SkData> b64_data = SkData::MakeUninitialized(b64_size + 1);
char* b64_char = static_cast<char*>(b64_data->writable_data());
SkBase64::Encode(sksl.second->data(), sksl.second->size(), b64_char);
b64_char[b64_size] = 0; // make it null terminated for printing
rapidjson::Value shader_value(b64_char, response.GetAllocator());
rapidjson::Value shader_key(PersistentCache::SkKeyToFilePath(*sksl.first),
response.GetAllocator());
shaders_json.AddMember(shader_key, shader_value, response.GetAllocator());
}
response.AddMember("SkSLs", shaders_json, response.GetAllocator());
return true;
}
// Service protocol handler
bool Shell::OnServiceProtocolSetAssetBundlePath(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response) {
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
if (params.count("assetDirectory") == 0) {
ServiceProtocolParameterError(response,
"'assetDirectory' parameter is missing.");
return false;
}
auto& allocator = response.GetAllocator();
response.SetObject();
auto asset_manager = std::make_shared<AssetManager>();
asset_manager->PushFront(std::make_unique<DirectoryAssetBundle>(
fml::OpenDirectory(params.at("assetDirectory").data(), false,
fml::FilePermission::kRead)));
if (engine_->UpdateAssetManager(std::move(asset_manager))) {
response.AddMember("type", "Success", allocator);
auto new_description = GetServiceProtocolDescription();
rapidjson::Value view(rapidjson::kObjectType);
new_description.Write(this, view, allocator);
response.AddMember("view", view, allocator);
return true;
} else {
FML_DLOG(ERROR) << "Could not update asset directory.";
ServiceProtocolFailureError(response, "Could not update asset directory.");
return false;
}
FML_DCHECK(false);
return false;
}
Rasterizer::ScreenshotType screenshot_type,
bool base64_encode) {
TRACE_EVENT0("flutter", "Shell::Screenshot");
Rasterizer::ScreenshotType screenshot_type, bool base64_encode) {
TRACE_EVENT0("uiwidgets", "Shell::Screenshot");
fml::AutoResetWaitableEvent latch;
Rasterizer::Screenshot screenshot;
fml::TaskRunner::RunNowOrPostTask(

std::unique_lock<std::mutex> lock(waiting_for_first_frame_mutex_);
bool success = waiting_for_first_frame_condition_.wait_for(
lock, std::chrono::milliseconds(timeout.ToMilliseconds()),
[& waiting_for_first_frame = waiting_for_first_frame_] {
[&waiting_for_first_frame = waiting_for_first_frame_] {
return !waiting_for_first_frame.load();
});
if (success) {

if (!engine_) {
return false;
}
engine_->GetFontCollection().GetFontCollection()->SetupDefaultFontManager();
engine_->GetFontCollection().GetFontCollection()->ClearFontFamilyCache();
// engine_->GetFontCollection().GetFontCollection()->SetupDefaultFontManager();
// engine_->GetFontCollection().GetFontCollection()->ClearFontFamilyCache();
// After system fonts are reloaded, we send a system channel message
// to notify flutter framework.
rapidjson::Document document;

document.Accept(writer);
std::string message = buffer.GetString();
fml::RefPtr<PlatformMessage> fontsChangeMessage =
fml::MakeRefCounted<flutter::PlatformMessage>(
fml::MakeRefCounted<PlatformMessage>(
kSystemChannel, std::vector<uint8_t>(message.begin(), message.end()),
nullptr);

return is_gpu_disabled_sync_switch_;
}
} // namespace flutter
} // namespace uiwidgets

335
engine/src/shell/common/shell.h


class Shell final : public PlatformView::Delegate,
public Animator::Delegate,
public Engine::Delegate,
public Rasterizer::Delegate,
public ServiceProtocol::Handler {
public Rasterizer::Delegate {
//----------------------------------------------------------------------------
/// @brief Creates a shell instance using the provided settings. The
/// callbacks to create the various shell subcomponents will be
/// called on the appropriate threads before this method returns.
/// If this is the first instance of a shell in the process, this
/// call also bootstraps the Dart VM.
///
/// @param[in] task_runners The task runners
/// @param[in] settings The settings
/// @param[in] on_create_platform_view The callback that must return a
/// platform view. This will be called on
/// the platform task runner before this
/// method returns.
/// @param[in] on_create_rasterizer That callback that must provide a
/// valid rasterizer. This will be called
/// on the render task runner before this
/// method returns.
///
/// @return A full initialized shell if the settings and callbacks are
/// valid. The root isolate has been created but not yet launched.
/// It may be launched by obtaining the engine weak pointer and
/// posting a task onto the UI task runner with a valid run
/// configuration to run the isolate. The embedder must always
/// check the validity of the shell (using the IsSetup call)
/// immediately after getting a pointer to it.
///
TaskRunners task_runners,
Settings settings,
TaskRunners task_runners, Settings settings,
//----------------------------------------------------------------------------
/// @brief Creates a shell instance using the provided settings. The
/// callbacks to create the various shell subcomponents will be
/// called on the appropriate threads before this method returns.
/// Unlike the simpler variant of this factory method, this method
/// allows for specification of window data. If this is the first
/// instance of a shell in the process, this call also bootstraps
/// the Dart VM.
///
/// @param[in] task_runners The task runners
/// @param[in] window_data The default data for setting up
/// ui.Window that attached to this
/// intance.
/// @param[in] settings The settings
/// @param[in] on_create_platform_view The callback that must return a
/// platform view. This will be called on
/// the platform task runner before this
/// method returns.
/// @param[in] on_create_rasterizer That callback that must provide a
/// valid rasterizer. This will be called
/// on the render task runner before this
/// method returns.
///
/// @return A full initialized shell if the settings and callbacks are
/// valid. The root isolate has been created but not yet launched.
/// It may be launched by obtaining the engine weak pointer and
/// posting a task onto the UI task runner with a valid run
/// configuration to run the isolate. The embedder must always
/// check the validity of the shell (using the IsSetup call)
/// immediately after getting a pointer to it.
///
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
CreateCallback<PlatformView> on_create_platform_view,
CreateCallback<Rasterizer> on_create_rasterizer);
//----------------------------------------------------------------------------
/// @brief Creates a shell instance using the provided settings. The
/// callbacks to create the various shell subcomponents will be
/// called on the appropriate threads before this method returns.
/// Unlike the simpler variant of this factory method, this method
/// allows for the specification of an isolate snapshot that
/// cannot be adequately described in the settings. This call also
/// requires the specification of a running VM instance.
///
/// @param[in] task_runners The task runners
/// @param[in] window_data The default data for setting up
/// ui.Window that attached to this
/// intance.
/// @param[in] settings The settings
/// @param[in] isolate_snapshot A custom isolate snapshot. Takes
/// precedence over any snapshots
/// specified in the settings.
/// @param[in] on_create_platform_view The callback that must return a
/// platform view. This will be called on
/// the platform task runner before this
/// method returns.
/// @param[in] on_create_rasterizer That callback that must provide a
/// valid rasterizer. This will be called
/// on the render task runner before this
/// method returns.
/// @param[in] vm A running VM instance.
///
/// @return A full initialized shell if the settings and callbacks are
/// valid. The root isolate has been created but not yet launched.
/// It may be launched by obtaining the engine weak pointer and
/// posting a task onto the UI task runner with a valid run
/// configuration to run the isolate. The embedder must always
/// check the validity of the shell (using the IsSetup call)
/// immediately after getting a pointer to it.
///
static std::unique_ptr<Shell> Create(
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
TaskRunners task_runners, const WindowData window_data, Settings settings,
const CreateCallback<Rasterizer>& on_create_rasterizer,
DartVMRef vm);
const CreateCallback<Rasterizer>& on_create_rasterizer);
//----------------------------------------------------------------------------
/// @brief Destroys the shell. This is a synchronous operation and
/// synchronous barrier blocks are introduced on the various
/// threads to ensure shutdown of all shell sub-components before
/// this method returns.
///
//----------------------------------------------------------------------------
/// @brief Starts an isolate for the given RunConfiguration.
///
//----------------------------------------------------------------------------
/// @brief Starts an isolate for the given RunConfiguration. The
/// result_callback will be called with the status of the
/// operation.
///
//------------------------------------------------------------------------------
/// @return The settings used to launch this shell.
///
//------------------------------------------------------------------------------
/// @brief If callers wish to interact directly with any shell
/// subcomponents, they must (on the platform thread) obtain a
/// task runner that the component is designed to run on and a
/// weak pointer to that component. They may then post a task to
/// that task runner, do the validity check on that task runner
/// before performing any operation on that component. This
/// accessor allows callers to access the task runners for this
/// shell.
///
/// @return The task runners current in use by the shell.
///
//----------------------------------------------------------------------------
/// @brief Rasterizers may only be accessed on the GPU task runner.
///
/// @return A weak pointer to the rasterizer.
///
//------------------------------------------------------------------------------
/// @brief Engines may only be accessed on the UI thread. This method is
/// deprecated, and implementers should instead use other API
/// available on the Shell or the PlatformView.
///
/// @return A weak pointer to the engine.
///
//----------------------------------------------------------------------------
/// @brief Platform views may only be accessed on the platform task
/// runner.
///
/// @return A weak pointer to the platform view.
///
// Embedders should call this under low memory conditions to free up
// internal caches used.
//
// This method posts a task to the raster threads to signal the Rasterizer to
// free resources.
//----------------------------------------------------------------------------
/// @brief Used by embedders to notify that there is a low memory
/// warning. The shell will attempt to purge caches. Current, only
/// the rasterizer cache is purged.
//----------------------------------------------------------------------------
/// @brief Used by embedders to check if all shell subcomponents are
/// initialized. It is the embedder's responsibility to make this
/// call before accessing any other shell method. A shell that is
/// not setup must be discarded and another one created with
/// updated settings.
///
/// @return Returns if the shell has been setup. Once set up, this does
/// not change for the life-cycle of the shell.
///
//----------------------------------------------------------------------------
/// @brief Captures a screenshot and optionally Base64 encodes the data
/// of the last layer tree rendered by the rasterizer in this
/// shell.
///
/// @param[in] type The type of screenshot to capture.
/// @param[in] base64_encode If the screenshot data should be base64
/// encoded.
///
/// @return The screenshot result.
///
//----------------------------------------------------------------------------
/// @brief Pauses the calling thread until the first frame is presented.
///
/// @return 'kOk' when the first frame has been presented before the timeout
/// successfully, 'kFailedPrecondition' if called from the GPU or UI
/// thread, 'kDeadlineExceeded' if there is a timeout.
///
//----------------------------------------------------------------------------
/// @brief Used by embedders to reload the system fonts in
/// FontCollection.
/// It also clears the cached font families and send system
/// channel message to framework to rebuild affected widgets.
///
/// @return Returns if shell reloads system fonts successfully.
///
//----------------------------------------------------------------------------
/// @brief Used by embedders to get the last error from the Dart UI
/// Isolate, if one exists.
///
/// @return Returns the last error code from the UI Isolate.
///
std::optional<DartErrorCode> GetUIIsolateLastError() const;
//----------------------------------------------------------------------------
/// @brief Used by embedders to check if the Engine is running and has
/// any live ports remaining. For example, the Flutter tester uses
/// this method to check whether it should continue to wait for
/// a running test or not.
///
/// @return Returns if the shell has an engine and the engine has any live
/// Dart ports.
///
bool EngineHasLivePorts() const;
//----------------------------------------------------------------------------
/// @brief Accessor for the disable GPU SyncSwitch
//----------------------------------------------------------------------------
/// @brief Get a pointer to the Dart VM used by this running shell
/// instance.
///
/// @return The Dart VM pointer.
///
DartVM* GetDartVM();
using ServiceProtocolHandler =
std::function<bool(const ServiceProtocol::Handler::ServiceProtocolMap&,
rapidjson::Document&)>;
DartVMRef vm_;
std::unique_ptr<PlatformView> platform_view_; // on platform task runner
std::unique_ptr<Engine> engine_; // on UI task runner
std::unique_ptr<Rasterizer> rasterizer_; // on GPU task runner

fml::WeakPtr<PlatformView>
weak_platform_view_; // to be shared across threads
std::unordered_map<std::string_view, // method
std::pair<fml::RefPtr<fml::TaskRunner>,
ServiceProtocolHandler> // task-runner/function
// pair
>
service_protocol_handlers_;
bool is_setup_ = false;
uint64_t next_pointer_flow_id_ = 0;

// How many frames have been timed since last report.
size_t UnreportedFramesCount() const;
Shell(DartVMRef vm, TaskRunners task_runners, Settings settings);
Shell(TaskRunners task_runners, Settings settings);
DartVMRef vm,
TaskRunners task_runners,
const WindowData window_data,
Settings settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
TaskRunners task_runners, const WindowData window_data, Settings settings,
const Shell::CreateCallback<PlatformView>& on_create_platform_view,
const Shell::CreateCallback<Rasterizer>& on_create_rasterizer);

// |PlatformView::Delegate|
void OnPlatformViewDispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet) override;
// |PlatformView::Delegate|
void OnPlatformViewDispatchSemanticsAction(
int32_t id,
SemanticsAction action,
std::vector<uint8_t> args) override;
// |PlatformView::Delegate|
void OnPlatformViewSetSemanticsEnabled(bool enabled) override;
void OnPlatformViewRegisterTexture(
std::shared_ptr<flutter::Texture> texture) override;
void OnPlatformViewRegisterTexture(std::shared_ptr<Texture> texture) override;
// |PlatformView::Delegate|
void OnPlatformViewUnregisterTexture(int64_t texture_id) override;

void OnAnimatorNotifyIdle(int64_t deadline) override;
// |Animator::Delegate|
void OnAnimatorDraw(
fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline) override;
void OnAnimatorDraw(fml::RefPtr<Pipeline<LayerTree>> pipeline) override;
void OnEngineUpdateSemantics(
SemanticsNodeUpdates update,
CustomAccessibilityActionUpdates actions) override;
// |Engine::Delegate|
void OnEngineHandlePlatformMessage(
fml::RefPtr<PlatformMessage> message) override;

void OnPreEngineRestart() override;
// |Engine::Delegate|
void UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) override;
// |Engine::Delegate|
void SetNeedsReportTimings(bool value) override;
// |Rasterizer::Delegate|

fml::Milliseconds GetFrameBudget() override;
// |ServiceProtocol::Handler|
fml::RefPtr<fml::TaskRunner> GetServiceProtocolHandlerTaskRunner(
std::string_view method) const override;
// |ServiceProtocol::Handler|
bool HandleServiceProtocolMessage(
std::string_view method, // one if the extension names specified above.
const ServiceProtocolMap& params,
rapidjson::Document& response) override;
// |ServiceProtocol::Handler|
ServiceProtocol::Handler::Description GetServiceProtocolDescription()
const override;
// Service protocol handler
bool OnServiceProtocolScreenshot(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolScreenshotSKP(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolRunInView(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolFlushUIThreadTasks(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolSetAssetBundlePath(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
bool OnServiceProtocolGetDisplayRefreshRate(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
// Service protocol handler
//
// The returned SkSLs are base64 encoded. Decode before storing them to files.
bool OnServiceProtocolGetSkSLs(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document& response);
fml::WeakPtrFactory<Shell> weak_factory_;
// For accessing the Shell via the raster thread, necessary for various

friend class testing::ShellTest;
} // namespace flutter
#endif // SHELL_COMMON_SHELL_H_
} // namespace uiwidgets

2
engine/src/shell/common/vsync_waiter.h


virtual float GetDisplayRefreshRate() const;
protected:
friend class VsyncWaiterEmbedder;
// On some backends, the |FireCallback| needs to be made from a static C
// method.
// TODO(kg):

3
com.unity.uiwidgets/Runtime/engine2.meta


fileFormatVersion: 2
guid: ffb851d47f1449fa9ea328aa58f27be7
timeCreated: 1597215228

7
engine/src/runtime/start_up.cc


#include "start_up.h"
namespace uiwidgets {
int64_t engine_main_enter_ts = 0;
} // namespace uiwidgets

9
engine/src/runtime/start_up.h


#pragma once
#include <stdint.h>
namespace uiwidgets {
extern int64_t engine_main_enter_ts;
} // namespace uiwidgets

194
engine/src/shell/common/canvas_spy.cc


#include "canvas_spy.h"
namespace uiwidgets {
CanvasSpy::CanvasSpy(SkCanvas* target_canvas) {
SkISize canvas_size = target_canvas->getBaseLayerSize();
n_way_canvas_ =
std::make_unique<SkNWayCanvas>(canvas_size.width(), canvas_size.height());
did_draw_canvas_ = std::make_unique<DidDrawCanvas>(canvas_size.width(),
canvas_size.height());
n_way_canvas_->addCanvas(target_canvas);
n_way_canvas_->addCanvas(did_draw_canvas_.get());
}
SkCanvas* CanvasSpy::GetSpyingCanvas() { return n_way_canvas_.get(); }
DidDrawCanvas::DidDrawCanvas(int width, int height)
: SkCanvasVirtualEnforcer<SkNoDrawCanvas>(width, height) {}
DidDrawCanvas::~DidDrawCanvas() {}
void DidDrawCanvas::MarkDrawIfNonTransparentPaint(const SkPaint& paint) {
bool isTransparent = paint.getAlpha() == 0;
did_draw_ |= !isTransparent;
}
bool CanvasSpy::DidDrawIntoCanvas() {
return did_draw_canvas_->DidDrawIntoCanvas();
}
bool DidDrawCanvas::DidDrawIntoCanvas() { return did_draw_; }
void DidDrawCanvas::willSave() {}
SkCanvas::SaveLayerStrategy DidDrawCanvas::getSaveLayerStrategy(
const SaveLayerRec& rec) {
return kNoLayer_SaveLayerStrategy;
}
bool DidDrawCanvas::onDoSaveBehind(const SkRect* bounds) { return false; }
void DidDrawCanvas::willRestore() {}
void DidDrawCanvas::didConcat(const SkMatrix& matrix) {}
void DidDrawCanvas::didConcat44(const SkM44&) {}
void DidDrawCanvas::didScale(SkScalar, SkScalar) {}
void DidDrawCanvas::didTranslate(SkScalar, SkScalar) {}
void DidDrawCanvas::didSetMatrix(const SkMatrix& matrix) {}
void DidDrawCanvas::onClipRect(const SkRect& rect, SkClipOp op,
ClipEdgeStyle edgeStyle) {}
void DidDrawCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op,
ClipEdgeStyle edgeStyle) {}
void DidDrawCanvas::onClipPath(const SkPath& path, SkClipOp op,
ClipEdgeStyle edgeStyle) {}
void DidDrawCanvas::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) {}
void DidDrawCanvas::onDrawPaint(const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawBehind(const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawPoints(PointMode mode, size_t count,
const SkPoint pts[], const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawArc(const SkRect& rect, SkScalar startAngle,
SkScalar sweepAngle, bool useCenter,
const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawImage(const SkImage* image, SkScalar left,
SkScalar top, const SkPaint* paint) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawImageRect(const SkImage* image, const SkRect* src,
const SkRect& dst, const SkPaint* paint,
SrcRectConstraint constraint) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center,
const SkRect& dst, const SkPaint* paint) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawImageLattice(const SkImage* image,
const Lattice& lattice,
const SkRect& dst,
const SkPaint* paint) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x,
SkScalar y, const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawPicture(const SkPicture* picture,
const SkMatrix* matrix,
const SkPaint* paint) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawDrawable(SkDrawable* drawable,
const SkMatrix* matrix) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawVerticesObject(const SkVertices* vertices,
SkBlendMode bmode,
const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawPatch(const SkPoint cubics[12],
const SkColor colors[4],
const SkPoint texCoords[4], SkBlendMode bmode,
const SkPaint& paint) {
MarkDrawIfNonTransparentPaint(paint);
}
void DidDrawCanvas::onDrawAtlas(const SkImage* image, const SkRSXform xform[],
const SkRect tex[], const SkColor colors[],
int count, SkBlendMode bmode,
const SkRect* cull, const SkPaint* paint) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawShadowRec(const SkPath& path,
const SkDrawShadowRec& rec) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawAnnotation(const SkRect& rect, const char key[],
SkData* data) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
SkCanvas::QuadAAFlags aa,
const SkColor4f& color, SkBlendMode mode) {
did_draw_ = true;
}
void DidDrawCanvas::onDrawEdgeAAImageSet(const ImageSetEntry set[], int count,
const SkPoint dstClips[],
const SkMatrix preViewMatrices[],
const SkPaint* paint,
SrcRectConstraint constraint) {
did_draw_ = true;
}
void DidDrawCanvas::onFlush() {}
} // namespace uiwidgets

165
engine/src/shell/common/canvas_spy.h


#pragma once
#include "flutter/fml/macros.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkCanvasVirtualEnforcer.h"
#include "include/utils/SkNWayCanvas.h"
#include "include/utils/SkNoDrawCanvas.h"
namespace uiwidgets {
class DidDrawCanvas;
class CanvasSpy {
public:
CanvasSpy(SkCanvas* target_canvas);
bool DidDrawIntoCanvas();
SkCanvas* GetSpyingCanvas();
private:
std::unique_ptr<SkNWayCanvas> n_way_canvas_;
std::unique_ptr<DidDrawCanvas> did_draw_canvas_;
FML_DISALLOW_COPY_AND_ASSIGN(CanvasSpy);
};
class DidDrawCanvas final : public SkCanvasVirtualEnforcer<SkNoDrawCanvas> {
public:
DidDrawCanvas(int width, int height);
~DidDrawCanvas() override;
bool DidDrawIntoCanvas();
private:
bool did_draw_ = false;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void willSave() override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
bool onDoSaveBehind(const SkRect*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void willRestore() override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void didConcat(const SkMatrix&) override;
void didConcat44(const SkM44&) override;
void didScale(SkScalar, SkScalar) override;
void didTranslate(SkScalar, SkScalar) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void didSetMatrix(const SkMatrix&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
const SkPaint& paint) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkBlendMode,
const SkPaint& paint) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawPaint(const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawBehind(const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawPoints(PointMode, size_t count, const SkPoint pts[],
const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawRect(const SkRect&, const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawRegion(const SkRegion&, const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawOval(const SkRect&, const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawArc(const SkRect&, SkScalar, SkScalar, bool,
const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawRRect(const SkRRect&, const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawPath(const SkPath&, const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawImage(const SkImage*, SkScalar left, SkScalar top,
const SkPaint*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
const SkPaint*, SrcRectConstraint) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&,
const SkPaint*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
const SkPaint*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawVerticesObject(const SkVertices*, SkBlendMode,
const SkPaint&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[],
const SkColor[], int, SkBlendMode, const SkRect*,
const SkPaint*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onClipRegion(const SkRegion&, SkClipOp) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawPicture(const SkPicture*, const SkMatrix*,
const SkPaint*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawDrawable(SkDrawable*, const SkMatrix*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawEdgeAAQuad(const SkRect&, const SkPoint[4], SkCanvas::QuadAAFlags,
const SkColor4f&, SkBlendMode) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onDrawEdgeAAImageSet(const ImageSetEntry[], int count, const SkPoint[],
const SkMatrix[], const SkPaint*,
SrcRectConstraint) override;
// |SkCanvasVirtualEnforcer<SkNoDrawCanvas>|
void onFlush() override;
void MarkDrawIfNonTransparentPaint(const SkPaint& paint);
FML_DISALLOW_COPY_AND_ASSIGN(DidDrawCanvas);
};
} // namespace uiwidgets

64
engine/src/shell/common/run_configuration.cc


#include "run_configuration.h"
#include <sstream>
#include <utility>
#include "assets/directory_asset_bundle.h"
#include "flutter/fml/file.h"
#include "flutter/fml/unique_fd.h"
namespace uiwidgets {
RunConfiguration RunConfiguration::InferFromSettings(const Settings& settings) {
auto asset_manager = std::make_shared<AssetManager>();
if (fml::UniqueFD::traits_type::IsValid(settings.assets_dir)) {
asset_manager->PushBack(std::make_unique<DirectoryAssetBundle>(
fml::Duplicate(settings.assets_dir)));
}
asset_manager->PushBack(
std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory(
settings.assets_path.c_str(), false, fml::FilePermission::kRead)));
return {asset_manager, settings.mono_entrypoint_callback};
}
RunConfiguration::RunConfiguration()
: RunConfiguration(std::make_shared<AssetManager>(), fml::closure()) {}
RunConfiguration::RunConfiguration(std::shared_ptr<AssetManager> asset_manager,
fml::closure mono_entrypoint_callback)
: asset_manager_(std::move(asset_manager)),
mono_entrypoint_callback_(std::move(mono_entrypoint_callback)) {}
RunConfiguration::RunConfiguration(RunConfiguration&&) = default;
RunConfiguration::~RunConfiguration() = default;
bool RunConfiguration::IsValid() const {
return static_cast<bool>(asset_manager_);
}
bool RunConfiguration::AddAssetResolver(
std::unique_ptr<AssetResolver> resolver) {
if (!resolver || !resolver->IsValid()) {
return false;
}
asset_manager_->PushBack(std::move(resolver));
return true;
}
std::shared_ptr<AssetManager> RunConfiguration::GetAssetManager() const {
return asset_manager_;
}
void RunConfiguration::SetMonoEntrypointCallback(fml::closure mono_entrypoint_callback) {
mono_entrypoint_callback_ = std::move(mono_entrypoint_callback);
}
fml::closure RunConfiguration::GetMonoEntrypointCallback() const {
return mono_entrypoint_callback_;
}
} // namespace uiwidgets

42
engine/src/shell/common/run_configuration.h


#pragma once
#include <memory>
#include <string>
#include "assets/asset_manager.h"
#include "assets/asset_resolver.h"
#include "common/settings.h"
#include "flutter/fml/macros.h"
namespace uiwidgets {
class RunConfiguration {
public:
static RunConfiguration InferFromSettings(const Settings& settings);
RunConfiguration();
RunConfiguration(std::shared_ptr<AssetManager> asset_manager, fml::closure mono_entrypoint_callback);
RunConfiguration(RunConfiguration&& config);
~RunConfiguration();
bool IsValid() const;
bool AddAssetResolver(std::unique_ptr<AssetResolver> resolver);
std::shared_ptr<AssetManager> GetAssetManager() const;
void SetMonoEntrypointCallback(fml::closure mono_entrypoint_callback);
fml::closure GetMonoEntrypointCallback() const;
private:
std::shared_ptr<AssetManager> asset_manager_;
fml::closure mono_entrypoint_callback_;
FML_DISALLOW_COPY_AND_ASSIGN(RunConfiguration);
};
} // namespace uiwidgets

24
engine/third_party/Unity/IUnityUIWidgets.h


#pragma once
#include "IUnityInterface.h"
#include "IUnityGraphics.h"
namespace UnityUIWidgets {
typedef void (*VoidCallback)();
typedef void (*VoidCallbackLong)(long);
UNITY_DECLARE_INTERFACE(IUnityUIWidgets) {
virtual ~IUnityUIWidgets() {}
virtual void SetUpdateCallback(VoidCallback callback) = 0;
virtual void SetVSyncCallback(VoidCallback callback) = 0;
virtual void SetWaitCallback(VoidCallbackLong callback) = 0;
virtual void SetWakeUpCallback(VoidCallback callback) = 0;
virtual void IssuePluginEventAndData(UnityRenderingEventAndData callback,
int eventId, void* data) = 0;
};
} // namespace UnityUIWidgets
UNITY_REGISTER_INTERFACE_GUID_IN_NAMESPACE(0x4C8BE8056B3C41D7ULL,
0xBC8BF5F2F0AC3532ULL,
IUnityUIWidgets, UnityUIWidgets)

154
com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs


using System;
using System.Runtime.InteropServices;
using AOT;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui2;
using UnityEngine;
using UnityEngine.UI;
using NativeBindings = Unity.UIWidgets.ui2.NativeBindings;
namespace Unity.UIWidgets.engine2 {
public class UIWidgetsPanel : RawImage {
public IntPtr isolate { get; private set; }
IntPtr _ptr;
GCHandle _handle;
RenderTexture _renderTexture;
int _width;
int _height;
float _devicePixelRatio;
int _currentWidth {
get { return Mathf.RoundToInt(rectTransform.rect.width * canvas.scaleFactor); }
}
int _currentHeight {
get { return Mathf.RoundToInt(rectTransform.rect.height * canvas.scaleFactor); }
}
float _currentDevicePixelRatio {
get {
float currentDpi = Screen.dpi;
if (currentDpi == 0) {
currentDpi = canvas.GetComponent<CanvasScaler>().fallbackScreenDPI;
}
return currentDpi / 96;
}
}
protected override void OnEnable() {
base.OnEnable();
_recreateRenderTexture(_currentWidth, _currentHeight, _currentDevicePixelRatio);
_handle = GCHandle.Alloc(this);
_ptr = UIWidgetsPanel_constructor((IntPtr) _handle, UIWidgetsPanel_entrypoint);
UIWidgetsPanel_onEnable(_ptr, _renderTexture.GetNativeTexturePtr(),
_width, _height, _devicePixelRatio);
}
protected virtual void main() {
}
public void entryPoint() {
try {
isolate = Isolate.current;
main();
}
catch (Exception ex) {
Debug.LogException(new Exception("exception in main", ex));
}
}
protected override void OnRectTransformDimensionsChange() {
if (_ptr != IntPtr.Zero) {
if (_recreateRenderTexture(_currentWidth, _currentHeight, _currentDevicePixelRatio)) {
UIWidgetsPanel_onRenderTexture(_ptr,
_renderTexture.GetNativeTexturePtr(),
_width, _height, _devicePixelRatio);
}
}
}
protected override void OnDisable() {
UIWidgetsPanel_onDisable(_ptr);
UIWidgetsPanel_dispose(_ptr);
_ptr = IntPtr.Zero;
_handle.Free();
_handle = default;
base.OnDisable();
}
bool _recreateRenderTexture(int width, int height, float devicePixelRatio) {
if (_renderTexture != null && _width == width && _height == height &&
_devicePixelRatio == devicePixelRatio) {
return false;
}
if (_renderTexture) {
_destroyRenderTexture();
}
_createRenderTexture(width, height, devicePixelRatio);
return true;
}
void _createRenderTexture(int width, int height, float devicePixelRatio) {
D.assert(_renderTexture == null);
var desc = new RenderTextureDescriptor(
width, height, RenderTextureFormat.ARGB32, 0) {
useMipMap = false,
autoGenerateMips = false,
};
_renderTexture = new RenderTexture(desc) {hideFlags = HideFlags.HideAndDontSave};
_renderTexture.Create();
_width = width;
_height = height;
_devicePixelRatio = devicePixelRatio;
texture = _renderTexture;
}
void _destroyRenderTexture() {
D.assert(_renderTexture != null);
texture = null;
ObjectUtils.SafeDestroy(_renderTexture);
_renderTexture = null;
}
delegate void UIWidgetsPanel_EntrypointCallback(IntPtr handle);
[MonoPInvokeCallback(typeof(UIWidgetsPanel_EntrypointCallback))]
static void UIWidgetsPanel_entrypoint(IntPtr handle) {
GCHandle gcHandle = (GCHandle) handle;
UIWidgetsPanel panel = (UIWidgetsPanel) gcHandle.Target;
panel.entryPoint();
}
[DllImport(NativeBindings.dllName)]
static extern IntPtr UIWidgetsPanel_constructor(IntPtr handle,
UIWidgetsPanel_EntrypointCallback entrypointCallback);
[DllImport(NativeBindings.dllName)]
static extern void UIWidgetsPanel_dispose(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern void UIWidgetsPanel_onEnable(IntPtr ptr,
IntPtr nativeTexturePtr, int width, int height, float dpi);
[DllImport(NativeBindings.dllName)]
static extern void UIWidgetsPanel_onDisable(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern void UIWidgetsPanel_onRenderTexture(
IntPtr ptr, IntPtr nativeTexturePtr, int width, int height, float dpi);
}
}

3
com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs.meta


fileFormatVersion: 2
guid: 305c123a2a944eba8f2b397a962323ff
timeCreated: 1597215247

48
engine/src/assets/asset_manager.cc


#include "asset_manager.h"
#include "flutter/fml/trace_event.h"
namespace uiwidgets {
AssetManager::AssetManager() = default;
AssetManager::~AssetManager() = default;
void AssetManager::PushFront(std::unique_ptr<AssetResolver> resolver) {
if (resolver == nullptr || !resolver->IsValid()) {
return;
}
resolvers_.push_front(std::move(resolver));
}
void AssetManager::PushBack(std::unique_ptr<AssetResolver> resolver) {
if (resolver == nullptr || !resolver->IsValid()) {
return;
}
resolvers_.push_back(std::move(resolver));
}
// |AssetResolver|
std::unique_ptr<fml::Mapping> AssetManager::GetAsMapping(
const std::string& asset_name) const {
if (asset_name.empty()) {
return std::unique_ptr<fml::Mapping>(nullptr);
}
TRACE_EVENT1("uiwidgets", "AssetManager::GetAsMapping", "name",
asset_name.c_str());
for (const auto& resolver : resolvers_) {
auto mapping = resolver->GetAsMapping(asset_name);
if (mapping != nullptr) {
return mapping;
}
}
FML_DLOG(WARNING) << "Could not find asset: " << asset_name;
return std::unique_ptr<fml::Mapping>(nullptr);
}
// |AssetResolver|
bool AssetManager::IsValid() const { return !resolvers_.empty(); }
} // namespace uiwidgets

35
engine/src/assets/asset_manager.h


#pragma once
#include <deque>
#include <memory>
#include <string>
#include "asset_resolver.h"
#include "flutter/fml/macros.h"
namespace uiwidgets {
class AssetManager final : public AssetResolver {
public:
AssetManager();
~AssetManager() override;
void PushFront(std::unique_ptr<AssetResolver> resolver);
void PushBack(std::unique_ptr<AssetResolver> resolver);
// |AssetResolver|
bool IsValid() const override;
// |AssetResolver|
std::unique_ptr<fml::Mapping> GetAsMapping(
const std::string& asset_name) const override;
private:
std::deque<std::unique_ptr<AssetResolver>> resolvers_;
FML_DISALLOW_COPY_AND_ASSIGN(AssetManager);
};
} // namespace uiwidgets

26
engine/src/assets/asset_resolver.h


#pragma once
#include <string>
#include <vector>
#include "flutter/fml/macros.h"
#include "flutter/fml/mapping.h"
namespace uiwidgets {
class AssetResolver {
public:
AssetResolver() = default;
virtual ~AssetResolver() = default;
virtual bool IsValid() const = 0;
[[nodiscard]] virtual std::unique_ptr<fml::Mapping> GetAsMapping(
const std::string& asset_name) const = 0;
private:
FML_DISALLOW_COPY_AND_ASSIGN(AssetResolver);
};
} // namespace uiwidgets

41
engine/src/assets/directory_asset_bundle.cc


#include "directory_asset_bundle.h"
#include <utility>
#include "flutter/fml/file.h"
#include "flutter/fml/mapping.h"
namespace uiwidgets {
DirectoryAssetBundle::DirectoryAssetBundle(fml::UniqueFD descriptor)
: descriptor_(std::move(descriptor)) {
if (!fml::IsDirectory(descriptor_)) {
return;
}
is_valid_ = true;
}
DirectoryAssetBundle::~DirectoryAssetBundle() = default;
// |AssetResolver|
bool DirectoryAssetBundle::IsValid() const { return is_valid_; }
// |AssetResolver|
std::unique_ptr<fml::Mapping> DirectoryAssetBundle::GetAsMapping(
const std::string& asset_name) const {
if (!is_valid_) {
FML_DLOG(WARNING) << "Asset bundle was not valid.";
return std::unique_ptr<fml::Mapping>(nullptr);
}
auto mapping = std::make_unique<fml::FileMapping>(fml::OpenFile(
descriptor_, asset_name.c_str(), false, fml::FilePermission::kRead));
if (!mapping->IsValid()) {
return std::unique_ptr<fml::Mapping>(nullptr);
}
return mapping;
}
} // namespace uiwidgets

30
engine/src/assets/directory_asset_bundle.h


#pragma once
#include "asset_resolver.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/ref_counted.h"
#include "flutter/fml/unique_fd.h"
namespace uiwidgets {
class DirectoryAssetBundle : public AssetResolver {
public:
explicit DirectoryAssetBundle(fml::UniqueFD descriptor);
~DirectoryAssetBundle() override;
private:
const fml::UniqueFD descriptor_;
bool is_valid_ = false;
// |AssetResolver|
bool IsValid() const override;
// |AssetResolver|
std::unique_ptr<fml::Mapping> GetAsMapping(
const std::string& asset_name) const override;
FML_DISALLOW_COPY_AND_ASSIGN(DirectoryAssetBundle);
};
} // namespace uiwidgets

14
engine/src/shell/gpu/gpu_surface_delegate.h


#pragma once
#include "flow/embedded_views.h"
namespace uiwidgets {
class GPUSurfaceDelegate {
public:
virtual ~GPUSurfaceDelegate() {}
virtual ExternalViewEmbedder* GetExternalViewEmbedder() = 0;
};
} // namespace uiwidgets

328
engine/src/shell/gpu/gpu_surface_gl.cc


#include "gpu_surface_gl.h"
#include "flutter/fml/base32.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/size.h"
#include "flutter/fml/trace_event.h"
#include "include/core/SkColorFilter.h"
#include "include/core/SkSurface.h"
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrContextOptions.h"
#include "shell/common/persistent_cache.h"
// These are common defines present on all OpenGL headers. However, we don't
// want to perform GL header reasolution on each platform we support. So just
// define these upfront. It is unlikely we will need more. But, if we do, we can
// add the same here.
#define GPU_GL_RGBA8 0x8058
#define GPU_GL_RGBA4 0x8056
#define GPU_GL_RGB565 0x8D62
namespace uiwidgets {
// Default maximum number of budgeted resources in the cache.
static const int kGrCacheMaxCount = 8192;
// Default maximum number of bytes of GPU memory of budgeted resources in the
// cache.
// The shell will dynamically increase or decrease this cache based on the
// viewport size, unless a user has specifically requested a size on the Skia
// system channel.
static const size_t kGrCacheMaxByteSize = 24 * (1 << 20);
GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate,
bool render_to_surface)
: delegate_(delegate),
render_to_surface_(render_to_surface),
weak_factory_(this) {
if (!delegate_->GLContextMakeCurrent()) {
FML_LOG(ERROR)
<< "Could not make the context current to setup the gr context.";
return;
}
GrContextOptions options;
if (PersistentCache::cache_sksl()) {
FML_LOG(INFO) << "Cache SkSL";
options.fShaderCacheStrategy = GrContextOptions::ShaderCacheStrategy::kSkSL;
}
PersistentCache::MarkStrategySet();
options.fPersistentCache = PersistentCache::GetCacheForProcess();
options.fAvoidStencilBuffers = true;
// To get video playback on the widest range of devices, we limit Skia to
// ES2 shading language when the ES3 external image extension is missing.
options.fPreferExternalImagesOverES3 = true;
// TODO(goderbauer): remove option when skbug.com/7523 is fixed.
// A similar work-around is also used in shell/common/io_manager.cc.
options.fDisableGpuYUVConversion = true;
auto context = GrContext::MakeGL(delegate_->GetGLInterface(), options);
if (context == nullptr) {
FML_LOG(ERROR) << "Failed to setup Skia Gr context.";
return;
}
context_ = std::move(context);
context_->setResourceCacheLimits(kGrCacheMaxCount, kGrCacheMaxByteSize);
context_owner_ = true;
valid_ = true;
std::vector<PersistentCache::SkSLCache> caches =
PersistentCache::GetCacheForProcess()->LoadSkSLs();
int compiled_count = 0;
for (const auto& cache : caches) {
compiled_count += context_->precompileShader(*cache.first, *cache.second);
}
FML_LOG(INFO) << "Found " << caches.size() << " SkSL shaders; precompiled "
<< compiled_count;
delegate_->GLContextClearCurrent();
}
GPUSurfaceGL::GPUSurfaceGL(sk_sp<GrContext> gr_context,
GPUSurfaceGLDelegate* delegate,
bool render_to_surface)
: delegate_(delegate),
context_(gr_context),
render_to_surface_(render_to_surface),
weak_factory_(this) {
if (!delegate_->GLContextMakeCurrent()) {
FML_LOG(ERROR)
<< "Could not make the context current to setup the gr context.";
return;
}
delegate_->GLContextClearCurrent();
valid_ = true;
context_owner_ = false;
}
GPUSurfaceGL::~GPUSurfaceGL() {
if (!valid_) {
return;
}
if (!delegate_->GLContextMakeCurrent()) {
FML_LOG(ERROR) << "Could not make the context current to destroy the "
"GrContext resources.";
return;
}
onscreen_surface_ = nullptr;
if (context_owner_) {
context_->releaseResourcesAndAbandonContext();
}
context_ = nullptr;
delegate_->GLContextClearCurrent();
}
// |Surface|
bool GPUSurfaceGL::IsValid() { return valid_; }
static SkColorType FirstSupportedColorType(GrContext* context,
GrGLenum* format) {
#define RETURN_IF_RENDERABLE(x, y) \
if (context->colorTypeSupportedAsSurface((x))) { \
*format = (y); \
return (x); \
}
RETURN_IF_RENDERABLE(kRGBA_8888_SkColorType, GPU_GL_RGBA8);
RETURN_IF_RENDERABLE(kARGB_4444_SkColorType, GPU_GL_RGBA4);
RETURN_IF_RENDERABLE(kRGB_565_SkColorType, GPU_GL_RGB565);
return kUnknown_SkColorType;
}
static sk_sp<SkSurface> WrapOnscreenSurface(GrContext* context,
const SkISize& size, intptr_t fbo) {
GrGLenum format;
const SkColorType color_type = FirstSupportedColorType(context, &format);
GrGLFramebufferInfo framebuffer_info = {};
framebuffer_info.fFBOID = static_cast<GrGLuint>(fbo);
framebuffer_info.fFormat = format;
GrBackendRenderTarget render_target(size.width(), // width
size.height(), // height
0, // sample count
0, // stencil bits (TODO)
framebuffer_info // framebuffer info
);
sk_sp<SkColorSpace> colorspace = SkColorSpace::MakeSRGB();
SkSurfaceProps surface_props(
SkSurfaceProps::InitType::kLegacyFontHost_InitType);
return SkSurface::MakeFromBackendRenderTarget(
context, // gr context
render_target, // render target
GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin, // origin
color_type, // color type
colorspace, // colorspace
&surface_props // surface properties
);
}
bool GPUSurfaceGL::CreateOrUpdateSurfaces(const SkISize& size) {
if (onscreen_surface_ != nullptr &&
size == SkISize::Make(onscreen_surface_->width(),
onscreen_surface_->height())) {
// Surface size appears unchanged. So bail.
return true;
}
// We need to do some updates.
TRACE_EVENT0("uiwidgets", "UpdateSurfacesSize");
// Either way, we need to get rid of previous surface.
onscreen_surface_ = nullptr;
if (size.isEmpty()) {
FML_LOG(ERROR) << "Cannot create surfaces of empty size.";
return false;
}
sk_sp<SkSurface> onscreen_surface;
onscreen_surface =
WrapOnscreenSurface(context_.get(), // GL context
size, // root surface size
delegate_->GLContextFBO() // window FBO ID
);
if (onscreen_surface == nullptr) {
// If the onscreen surface could not be wrapped. There is absolutely no
// point in moving forward.
FML_LOG(ERROR) << "Could not wrap onscreen surface.";
return false;
}
onscreen_surface_ = std::move(onscreen_surface);
return true;
}
// |Surface|
SkMatrix GPUSurfaceGL::GetRootTransformation() const {
return delegate_->GLContextSurfaceTransformation();
}
// |Surface|
std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
if (delegate_ == nullptr) {
return nullptr;
}
if (!delegate_->GLContextMakeCurrent()) {
FML_LOG(ERROR)
<< "Could not make the context current to acquire the frame.";
return nullptr;
}
// TODO(38466): Refactor GPU surface APIs take into account the fact that an
// external view embedder may want to render to the root surface.
if (!render_to_surface_) {
return std::make_unique<SurfaceFrame>(
nullptr, true, [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
return true;
});
}
const auto root_surface_transformation = GetRootTransformation();
sk_sp<SkSurface> surface =
AcquireRenderSurface(size, root_surface_transformation);
if (surface == nullptr) {
return nullptr;
}
surface->getCanvas()->setMatrix(root_surface_transformation);
SurfaceFrame::SubmitCallback submit_callback =
[weak = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame,
SkCanvas* canvas) {
return weak ? weak->PresentSurface(canvas) : false;
};
return std::make_unique<SurfaceFrame>(
surface, delegate_->SurfaceSupportsReadback(), submit_callback);
}
bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
if (delegate_ == nullptr || canvas == nullptr || context_ == nullptr) {
return false;
}
{
TRACE_EVENT0("uiwidgets", "SkCanvas::Flush");
onscreen_surface_->getCanvas()->flush();
onscreen_surface_->getContext()->submit(true);
}
if (!delegate_->GLContextPresent()) {
return false;
}
if (delegate_->GLContextFBOResetAfterPresent()) {
auto current_size =
SkISize::Make(onscreen_surface_->width(), onscreen_surface_->height());
// The FBO has changed, ask the delegate for the new FBO and do a surface
// re-wrap.
auto new_onscreen_surface =
WrapOnscreenSurface(context_.get(), // GL context
current_size, // root surface size
delegate_->GLContextFBO() // window FBO ID
);
if (!new_onscreen_surface) {
return false;
}
onscreen_surface_ = std::move(new_onscreen_surface);
}
return true;
}
sk_sp<SkSurface> GPUSurfaceGL::AcquireRenderSurface(
const SkISize& untransformed_size,
const SkMatrix& root_surface_transformation) {
const auto transformed_rect = root_surface_transformation.mapRect(
SkRect::MakeWH(untransformed_size.width(), untransformed_size.height()));
const auto transformed_size =
SkISize::Make(transformed_rect.width(), transformed_rect.height());
if (!CreateOrUpdateSurfaces(transformed_size)) {
return nullptr;
}
return onscreen_surface_;
}
// |Surface|
GrContext* GPUSurfaceGL::GetContext() { return context_.get(); }
// |Surface|
ExternalViewEmbedder* GPUSurfaceGL::GetExternalViewEmbedder() {
return delegate_->GetExternalViewEmbedder();
}
// |Surface|
bool GPUSurfaceGL::MakeRenderContextCurrent() {
return delegate_->GLContextMakeCurrent();
}
} // namespace uiwidgets

68
engine/src/shell/gpu/gpu_surface_gl.h


#pragma once
#include <functional>
#include <memory>
#include "flow/embedded_views.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "include/gpu/GrContext.h"
#include "shell/common/surface.h"
#include "shell/gpu/gpu_surface_gl_delegate.h"
namespace uiwidgets {
class GPUSurfaceGL : public Surface {
public:
GPUSurfaceGL(GPUSurfaceGLDelegate* delegate, bool render_to_surface);
// Creates a new GL surface reusing an existing GrContext.
GPUSurfaceGL(sk_sp<GrContext> gr_context, GPUSurfaceGLDelegate* delegate,
bool render_to_surface);
// |Surface|
~GPUSurfaceGL() override;
// |Surface|
bool IsValid() override;
// |Surface|
std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) override;
// |Surface|
SkMatrix GetRootTransformation() const override;
// |Surface|
GrContext* GetContext() override;
// |Surface|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
// |Surface|
bool MakeRenderContextCurrent() override;
private:
GPUSurfaceGLDelegate* delegate_;
sk_sp<GrContext> context_;
sk_sp<SkSurface> onscreen_surface_;
bool context_owner_;
// TODO(38466): Refactor GPU surface APIs take into account the fact that an
// external view embedder may want to render to the root surface. This is a
// hack to make avoid allocating resources for the root surface when an
// external view embedder is present.
const bool render_to_surface_;
bool valid_ = false;
fml::WeakPtrFactory<GPUSurfaceGL> weak_factory_;
bool CreateOrUpdateSurfaces(const SkISize& size);
sk_sp<SkSurface> AcquireRenderSurface(
const SkISize& untransformed_size,
const SkMatrix& root_surface_transformation);
bool PresentSurface(SkCanvas* canvas);
FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceGL);
};
} // namespace uiwidgets

100
engine/src/shell/gpu/gpu_surface_gl_delegate.cc


#pragma once
#include "gpu_surface_gl_delegate.h"
#include "include/gpu/gl/GrGLAssembleInterface.h"
namespace uiwidgets {
GPUSurfaceGLDelegate::~GPUSurfaceGLDelegate() = default;
bool GPUSurfaceGLDelegate::GLContextFBOResetAfterPresent() const {
return false;
}
bool GPUSurfaceGLDelegate::SurfaceSupportsReadback() const { return true; }
SkMatrix GPUSurfaceGLDelegate::GLContextSurfaceTransformation() const {
SkMatrix matrix;
matrix.setIdentity();
return matrix;
}
GPUSurfaceGLDelegate::GLProcResolver GPUSurfaceGLDelegate::GetGLProcResolver()
const {
return nullptr;
}
static bool IsProcResolverOpenGLES(
GPUSurfaceGLDelegate::GLProcResolver proc_resolver) {
// Version string prefix that identifies an OpenGL ES implementation.
#define GPU_GL_VERSION 0x1F02
constexpr char kGLESVersionPrefix[] = "OpenGL ES";
using GLGetStringProc = const char* (*)(uint32_t);
GLGetStringProc gl_get_string =
reinterpret_cast<GLGetStringProc>(proc_resolver("glGetString"));
FML_CHECK(gl_get_string)
<< "The GL proc resolver could not resolve glGetString";
const char* gl_version_string = gl_get_string(GPU_GL_VERSION);
FML_CHECK(gl_version_string)
<< "The GL proc resolver's glGetString(GL_VERSION) failed";
return strncmp(gl_version_string, kGLESVersionPrefix,
strlen(kGLESVersionPrefix)) == 0;
}
static sk_sp<const GrGLInterface> CreateGLInterface(
GPUSurfaceGLDelegate::GLProcResolver proc_resolver) {
if (proc_resolver == nullptr) {
// If there is no custom proc resolver, ask Skia to guess the native
// interface. This often leads to interesting results on most platforms.
return GrGLMakeNativeInterface();
}
struct ProcResolverContext {
GPUSurfaceGLDelegate::GLProcResolver resolver;
};
ProcResolverContext context = {proc_resolver};
GrGLGetProc gl_get_proc = [](void* context,
const char gl_proc_name[]) -> GrGLFuncPtr {
auto proc_resolver_context =
reinterpret_cast<ProcResolverContext*>(context);
return reinterpret_cast<GrGLFuncPtr>(
proc_resolver_context->resolver(gl_proc_name));
};
// glGetString indicates an OpenGL ES interface.
if (IsProcResolverOpenGLES(proc_resolver)) {
return GrGLMakeAssembledGLESInterface(&context, gl_get_proc);
}
// Fallback to OpenGL.
if (auto interface = GrGLMakeAssembledGLInterface(&context, gl_get_proc)) {
return interface;
}
FML_LOG(ERROR) << "Could not create a valid GL interface.";
return nullptr;
}
sk_sp<const GrGLInterface> GPUSurfaceGLDelegate::GetGLInterface() const {
return CreateGLInterface(GetGLProcResolver());
}
sk_sp<const GrGLInterface>
GPUSurfaceGLDelegate::GetDefaultPlatformGLInterface() {
return CreateGLInterface(nullptr);
}
ExternalViewEmbedder* GPUSurfaceGLDelegate::GetExternalViewEmbedder() {
return nullptr;
}
} // namespace uiwidgets

65
engine/src/shell/gpu/gpu_surface_gl_delegate.h


#pragma once
#include "flow/embedded_views.h"
#include "flutter/fml/macros.h"
#include "include/core/SkMatrix.h"
#include "include/gpu/gl/GrGLInterface.h"
#include "shell/gpu/gpu_surface_delegate.h"
namespace uiwidgets {
class GPUSurfaceGLDelegate : public GPUSurfaceDelegate {
public:
~GPUSurfaceGLDelegate() override;
// |GPUSurfaceDelegate|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
// Called to make the main GL context current on the current thread.
virtual bool GLContextMakeCurrent() = 0;
// Called to clear the current GL context on the thread. This may be called on
// either the GPU or IO threads.
virtual bool GLContextClearCurrent() = 0;
// Called to present the main GL surface. This is only called for the main GL
// context and not any of the contexts dedicated for IO.
virtual bool GLContextPresent() = 0;
// The ID of the main window bound framebuffer. Typically FBO0.
virtual intptr_t GLContextFBO() const = 0;
// The rendering subsystem assumes that the ID of the main window bound
// framebuffer remains constant throughout. If this assumption in incorrect,
// embedders are required to return true from this method. In such cases,
// GLContextFBO() will be called again to acquire the new FBO ID for rendering
// subsequent frames.
virtual bool GLContextFBOResetAfterPresent() const;
// Indicates whether or not the surface supports pixel readback as used in
// circumstances such as a BackdropFilter.
virtual bool SurfaceSupportsReadback() const;
// A transformation applied to the onscreen surface before the canvas is
// flushed.
virtual SkMatrix GLContextSurfaceTransformation() const;
sk_sp<const GrGLInterface> GetGLInterface() const;
// TODO(chinmaygarde): The presence of this method is to work around the fact
// that not all platforms can accept a custom GL proc table. Migrate all
// platforms to move GL proc resolution to the embedder and remove this
// method.
static sk_sp<const GrGLInterface> GetDefaultPlatformGLInterface();
using GLProcResolver =
std::function<void* /* proc name */ (const char* /* proc address */)>;
// Provide a custom GL proc resolver. If no such resolver is present, Skia
// will attempt to do GL proc address resolution on its own. Embedders that
// have specific opinions on GL API selection or need to add their own
// instrumentation to specific GL calls can specify custom GL functions
// here.
virtual GLProcResolver GetGLProcResolver() const;
};
} // namespace uiwidgets

90
engine/src/shell/gpu/gpu_surface_software.cc


#include "gpu_surface_software.h"
#include <memory>
#include "flutter/fml/logging.h"
namespace uiwidgets {
GPUSurfaceSoftware::GPUSurfaceSoftware(GPUSurfaceSoftwareDelegate* delegate,
bool render_to_surface)
: delegate_(delegate),
render_to_surface_(render_to_surface),
weak_factory_(this) {}
GPUSurfaceSoftware::~GPUSurfaceSoftware() = default;
// |Surface|
bool GPUSurfaceSoftware::IsValid() { return delegate_ != nullptr; }
// |Surface|
std::unique_ptr<SurfaceFrame> GPUSurfaceSoftware::AcquireFrame(
const SkISize& logical_size) {
// TODO(38466): Refactor GPU surface APIs take into account the fact that an
// external view embedder may want to render to the root surface.
if (!render_to_surface_) {
return std::make_unique<SurfaceFrame>(
nullptr, true, [](const SurfaceFrame& surface_frame, SkCanvas* canvas) {
return true;
});
}
if (!IsValid()) {
return nullptr;
}
const auto size = SkISize::Make(logical_size.width(), logical_size.height());
sk_sp<SkSurface> backing_store = delegate_->AcquireBackingStore(size);
if (backing_store == nullptr) {
return nullptr;
}
if (size != SkISize::Make(backing_store->width(), backing_store->height())) {
return nullptr;
}
// If the surface has been scaled, we need to apply the inverse scaling to the
// underlying canvas so that coordinates are mapped to the same spot
// irrespective of surface scaling.
SkCanvas* canvas = backing_store->getCanvas();
canvas->resetMatrix();
SurfaceFrame::SubmitCallback on_submit =
[self = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame,
SkCanvas* canvas) -> bool {
// If the surface itself went away, there is nothing more to do.
if (!self || !self->IsValid() || canvas == nullptr) {
return false;
}
canvas->flush();
return self->delegate_->PresentBackingStore(surface_frame.SkiaSurface());
};
return std::make_unique<SurfaceFrame>(backing_store, true, on_submit);
}
// |Surface|
SkMatrix GPUSurfaceSoftware::GetRootTransformation() const {
// This backend does not currently support root surface transformations. Just
// return identity.
SkMatrix matrix;
matrix.reset();
return matrix;
}
// |Surface|
GrContext* GPUSurfaceSoftware::GetContext() {
// There is no GrContext associated with a software surface.
return nullptr;
}
// |Surface|
ExternalViewEmbedder* GPUSurfaceSoftware::GetExternalViewEmbedder() {
return delegate_->GetExternalViewEmbedder();
}
} // namespace uiwidgets

44
engine/src/shell/gpu/gpu_surface_software.h


#pragma once
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "shell/common/surface.h"
#include "shell/gpu/gpu_surface_software_delegate.h"
namespace uiwidgets {
class GPUSurfaceSoftware : public Surface {
public:
GPUSurfaceSoftware(GPUSurfaceSoftwareDelegate* delegate,
bool render_to_surface);
~GPUSurfaceSoftware() override;
// |Surface|
bool IsValid() override;
// |Surface|
std::unique_ptr<SurfaceFrame> AcquireFrame(const SkISize& size) override;
// |Surface|
SkMatrix GetRootTransformation() const override;
// |Surface|
GrContext* GetContext() override;
// |Surface|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
private:
GPUSurfaceSoftwareDelegate* delegate_;
// TODO(38466): Refactor GPU surface APIs take into account the fact that an
// external view embedder may want to render to the root surface. This is a
// hack to make avoid allocating resources for the root surface when an
// external view embedder is present.
const bool render_to_surface_;
fml::WeakPtrFactory<GPUSurfaceSoftware> weak_factory_;
FML_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceSoftware);
};
} // namespace uiwidgets

11
engine/src/shell/gpu/gpu_surface_software_delegate.cc


#include "gpu_surface_software_delegate.h"
namespace uiwidgets {
GPUSurfaceSoftwareDelegate::~GPUSurfaceSoftwareDelegate() = default;
ExternalViewEmbedder* GPUSurfaceSoftwareDelegate::GetExternalViewEmbedder() {
return nullptr;
}
} // namespace uiwidgets

22
engine/src/shell/gpu/gpu_surface_software_delegate.h


#pragma once
#include "flow/embedded_views.h"
#include "flutter/fml/macros.h"
#include "include/core/SkSurface.h"
#include "shell/gpu/gpu_surface_delegate.h"
namespace uiwidgets {
class GPUSurfaceSoftwareDelegate : public GPUSurfaceDelegate {
public:
~GPUSurfaceSoftwareDelegate() override;
// |GPUSurfaceDelegate|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
virtual sk_sp<SkSurface> AcquireBackingStore(const SkISize& size) = 0;
virtual bool PresentBackingStore(sk_sp<SkSurface> backing_store) = 0;
};
} // namespace uiwidgets

1001
engine/src/shell/platform/embedder/embedder.cc
文件差异内容过多而无法显示
查看文件

459
engine/src/shell/platform/embedder/embedder.h


#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#if defined(__cplusplus)
extern "C" {
#endif
typedef enum {
kSuccess = 0,
kInvalidLibraryVersion,
kInvalidArguments,
kInternalInconsistency,
} UIWidgetsEngineResult;
typedef enum {
kOpenGL,
kSoftware,
} UIWidgetsRendererType;
typedef enum {
kUIWidgetsAccessibilityFeatureAccessibleNavigation = 1 << 0,
kUIWidgetsAccessibilityFeatureInvertColors = 1 << 1,
kUIWidgetsAccessibilityFeatureDisableAnimations = 1 << 2,
kUIWidgetsAccessibilityFeatureBoldText = 1 << 3,
kUIWidgetsAccessibilityFeatureReduceMotion = 1 << 4,
} UIWidgetsAccessibilityFeature;
typedef enum {
kUIWidgetsTextDirectionUnknown = 0,
kUIWidgetsTextDirectionRTL = 1,
kUIWidgetsTextDirectionLTR = 2,
} UIWidgetsTextDirection;
typedef struct _UIWidgetsEngine* UIWidgetsEngine;
typedef struct {
float scaleX;
float skewX;
float transX;
float skewY;
float scaleY;
float transY;
float pers0;
float pers1;
float pers2;
} UIWidgetsTransformation;
typedef void (*VoidCallback)(void* /* user data */);
typedef enum {
kUIWidgetsOpenGLTargetTypeTexture,
kUIWidgetsOpenGLTargetTypeFramebuffer,
} UIWidgetsOpenGLTargetType;
typedef struct {
uint32_t target;
uint32_t name;
uint32_t format;
void* user_data;
VoidCallback destruction_callback;
size_t width;
size_t height;
} UIWidgetsOpenGLTexture;
typedef struct {
uint32_t target;
uint32_t name;
void* user_data;
VoidCallback destruction_callback;
} UIWidgetsOpenGLFramebuffer;
typedef bool (*BoolCallback)(void* /* user data */);
typedef UIWidgetsTransformation (*TransformationCallback)(
void* /* user data */);
typedef uint32_t (*UIntCallback)(void* /* user data */);
typedef bool (*SoftwareSurfacePresentCallback)(void* /* user data */,
const void* /* allocation */,
size_t /* row bytes */,
size_t /* height */);
typedef void* (*ProcResolver)(void* /* user data */, const char* /* name */);
typedef bool (*TextureFrameCallback)(void* /* user data */,
int64_t /* texture identifier */,
size_t /* width */, size_t /* height */,
UIWidgetsOpenGLTexture* /* texture out */);
typedef void (*VsyncCallback)(void* /* user data */, intptr_t /* baton */);
typedef struct {
size_t struct_size;
BoolCallback make_current;
BoolCallback clear_current;
BoolCallback present;
UIntCallback fbo_callback;
BoolCallback make_resource_current;
bool fbo_reset_after_present;
TransformationCallback surface_transformation;
ProcResolver gl_proc_resolver;
TextureFrameCallback gl_external_texture_frame_callback;
} UIWidgetsOpenGLRendererConfig;
typedef struct {
size_t struct_size;
SoftwareSurfacePresentCallback surface_present_callback;
} UIWidgetsSoftwareRendererConfig;
typedef struct {
UIWidgetsRendererType type;
union {
UIWidgetsOpenGLRendererConfig open_gl;
UIWidgetsSoftwareRendererConfig software;
};
} UIWidgetsRendererConfig;
typedef struct {
size_t struct_size;
size_t width;
size_t height;
float pixel_ratio;
} UIWidgetsWindowMetricsEvent;
typedef enum {
kCancel,
kUp,
kDown,
kMove,
kAdd,
kRemove,
kHover,
} UIWidgetsPointerPhase;
typedef enum {
kUIWidgetsPointerDeviceKindMouse = 1,
kUIWidgetsPointerDeviceKindTouch,
} UIWidgetsPointerDeviceKind;
typedef enum {
kUIWidgetsPointerButtonMousePrimary = 1 << 0,
kUIWidgetsPointerButtonMouseSecondary = 1 << 1,
kUIWidgetsPointerButtonMouseMiddle = 1 << 2,
kUIWidgetsPointerButtonMouseBack = 1 << 3,
kUIWidgetsPointerButtonMouseForward = 1 << 4,
} UIWidgetsPointerMouseButtons;
typedef enum {
kUIWidgetsPointerSignalKindNone,
kUIWidgetsPointerSignalKindScroll,
} UIWidgetsPointerSignalKind;
typedef struct {
size_t struct_size;
UIWidgetsPointerPhase phase;
size_t timestamp;
float x;
float y;
int32_t device;
UIWidgetsPointerSignalKind signal_kind;
float scroll_delta_x;
float scroll_delta_y;
UIWidgetsPointerDeviceKind device_kind;
int64_t buttons;
} UIWidgetsPointerEvent;
struct _UIWidgetsPlatformMessageResponseHandle;
typedef struct _UIWidgetsPlatformMessageResponseHandle
UIWidgetsPlatformMessageResponseHandle;
typedef struct {
size_t struct_size;
const char* channel;
const uint8_t* message;
size_t message_size;
const UIWidgetsPlatformMessageResponseHandle* response_handle;
} UIWidgetsPlatformMessage;
typedef void (*UIWidgetsPlatformMessageCallback)(
const UIWidgetsPlatformMessage* /* message*/, void* /* user data */);
typedef void (*UIWidgetsDataCallback)(const uint8_t* /* data */,
size_t /* size */, void* /* user data */);
typedef struct {
float left;
float top;
float right;
float bottom;
} UIWidgetsRect;
typedef struct {
float x;
float y;
} UIWidgetsPoint;
typedef struct {
float width;
float height;
} UIWidgetsSize;
typedef struct {
UIWidgetsRect rect;
UIWidgetsSize upper_left_corner_radius;
UIWidgetsSize upper_right_corner_radius;
UIWidgetsSize lower_right_corner_radius;
UIWidgetsSize lower_left_corner_radius;
} UIWidgetsRoundedRect;
typedef int64_t UIWidgetsPlatformViewIdentifier;
typedef struct _UIWidgetsTaskRunner* UIWidgetsTaskRunner;
typedef struct {
UIWidgetsTaskRunner runner;
uint64_t task;
} UIWidgetsTask;
typedef void (*UIWidgetsTaskRunnerPostTaskCallback)(
UIWidgetsTask /* task */, uint64_t /* target time nanos */,
void* /* user data */);
typedef struct {
size_t struct_size;
void* user_data;
BoolCallback runs_task_on_current_thread_callback;
UIWidgetsTaskRunnerPostTaskCallback post_task_callback;
size_t identifier;
} UIWidgetsTaskRunnerDescription;
typedef struct {
size_t struct_size;
const UIWidgetsTaskRunnerDescription* platform_task_runner;
const UIWidgetsTaskRunnerDescription* ui_task_runner;
const UIWidgetsTaskRunnerDescription* render_task_runner;
} UIWidgetsCustomTaskRunners;
typedef struct {
UIWidgetsOpenGLTargetType type;
union {
UIWidgetsOpenGLTexture texture;
UIWidgetsOpenGLFramebuffer framebuffer;
};
} UIWidgetsOpenGLBackingStore;
typedef struct {
const void* allocation;
size_t row_bytes;
size_t height;
void* user_data;
VoidCallback destruction_callback;
} UIWidgetsSoftwareBackingStore;
typedef enum {
kUIWidgetsPlatformViewMutationTypeOpacity,
kUIWidgetsPlatformViewMutationTypeClipRect,
kUIWidgetsPlatformViewMutationTypeClipRoundedRect,
kUIWidgetsPlatformViewMutationTypeTransformation,
} UIWidgetsPlatformViewMutationType;
typedef struct {
UIWidgetsPlatformViewMutationType type;
union {
double opacity;
UIWidgetsRect clip_rect;
UIWidgetsRoundedRect clip_rounded_rect;
UIWidgetsTransformation transformation;
};
} UIWidgetsPlatformViewMutation;
typedef struct {
size_t struct_size;
UIWidgetsPlatformViewIdentifier identifier;
size_t mutations_count;
const UIWidgetsPlatformViewMutation** mutations;
} UIWidgetsPlatformView;
typedef enum {
kUIWidgetsBackingStoreTypeOpenGL,
kUIWidgetsBackingStoreTypeSoftware,
} UIWidgetsBackingStoreType;
typedef struct {
size_t struct_size;
void* user_data;
UIWidgetsBackingStoreType type;
bool did_update;
union {
UIWidgetsOpenGLBackingStore open_gl;
UIWidgetsSoftwareBackingStore software;
};
} UIWidgetsBackingStore;
typedef struct {
size_t struct_size;
UIWidgetsSize size;
} UIWidgetsBackingStoreConfig;
typedef enum {
kUIWidgetsLayerContentTypeBackingStore,
kUIWidgetsLayerContentTypePlatformView,
} UIWidgetsLayerContentType;
typedef struct {
size_t struct_size;
UIWidgetsLayerContentType type;
union {
const UIWidgetsBackingStore* backing_store;
const UIWidgetsPlatformView* platform_view;
};
UIWidgetsPoint offset;
UIWidgetsSize size;
} UIWidgetsLayer;
typedef bool (*UIWidgetsBackingStoreCreateCallback)(
const UIWidgetsBackingStoreConfig* config,
UIWidgetsBackingStore* backing_store_out, void* user_data);
typedef bool (*UIWidgetsBackingStoreCollectCallback)(
const UIWidgetsBackingStore* renderer, void* user_data);
typedef bool (*UIWidgetsLayersPresentCallback)(const UIWidgetsLayer** layers,
size_t layers_count,
void* user_data);
typedef struct {
size_t struct_size;
void* user_data;
UIWidgetsBackingStoreCreateCallback create_backing_store_callback;
UIWidgetsBackingStoreCollectCallback collect_backing_store_callback;
UIWidgetsLayersPresentCallback present_layers_callback;
} UIWidgetsCompositor;
typedef struct {
size_t struct_size;
const char* language_code;
const char* country_code;
const char* script_code;
const char* variant_code;
} UIWidgetsLocale;
typedef enum {
kUIWidgetsNativeThreadTypePlatform,
kUIWidgetsNativeThreadTypeRender,
kUIWidgetsNativeThreadTypeUI,
kUIWidgetsNativeThreadTypeWorker,
} UIWidgetsNativeThreadType;
typedef void (*UIWidgetsNativeThreadCallback)(UIWidgetsNativeThreadType type,
void* user_data);
typedef void (*UIWidgetsTaskObserverAdd)(intptr_t key, void* callback,
void* user_data);
typedef void (*UIWidgetsTaskObserverRemove)(intptr_t key, void* user_data);
typedef void (*UIWidgetsMonoEntrypointCallback)(void* user_data);
typedef struct {
size_t struct_size;
const char* assets_path;
const char* icu_data_path;
int command_line_argc;
const char* const* command_line_argv;
UIWidgetsPlatformMessageCallback platform_message_callback;
VoidCallback root_isolate_create_callback;
const char* persistent_cache_path;
bool is_persistent_cache_read_only;
VsyncCallback vsync_callback;
const UIWidgetsCustomTaskRunners* custom_task_runners;
const UIWidgetsCompositor* compositor;
UIWidgetsTaskObserverAdd task_observer_add;
UIWidgetsTaskObserverRemove task_observer_remove;
UIWidgetsMonoEntrypointCallback custom_mono_entrypoint;
UIWidgetsWindowMetricsEvent initial_window_metrics;
} UIWidgetsProjectArgs;
UIWidgetsEngineResult UIWidgetsEngineRun(const UIWidgetsRendererConfig* config,
const UIWidgetsProjectArgs* args,
void* user_data,
UIWidgetsEngine* engine_out);
UIWidgetsEngineResult UIWidgetsEngineShutdown(UIWidgetsEngine engine);
UIWidgetsEngineResult UIWidgetsEngineInitialize(
const UIWidgetsRendererConfig* config, const UIWidgetsProjectArgs* args,
void* user_data, UIWidgetsEngine* engine_out);
UIWidgetsEngineResult UIWidgetsEngineDeinitialize(UIWidgetsEngine engine);
UIWidgetsEngineResult UIWidgetsEngineRunInitialized(UIWidgetsEngine engine);
UIWidgetsEngineResult UIWidgetsEngineSendWindowMetricsEvent(
UIWidgetsEngine engine, const UIWidgetsWindowMetricsEvent* event);
UIWidgetsEngineResult UIWidgetsEngineSendPointerEvent(
UIWidgetsEngine engine, const UIWidgetsPointerEvent* events,
size_t events_count);
UIWidgetsEngineResult UIWidgetsEngineSendPlatformMessage(
UIWidgetsEngine engine, const UIWidgetsPlatformMessage* message);
UIWidgetsEngineResult UIWidgetsPlatformMessageCreateResponseHandle(
UIWidgetsEngine engine, UIWidgetsDataCallback data_callback,
void* user_data, UIWidgetsPlatformMessageResponseHandle** response_out);
UIWidgetsEngineResult UIWidgetsPlatformMessageReleaseResponseHandle(
UIWidgetsEngine engine, UIWidgetsPlatformMessageResponseHandle* response);
UIWidgetsEngineResult UIWidgetsEngineSendPlatformMessageResponse(
UIWidgetsEngine engine,
const UIWidgetsPlatformMessageResponseHandle* handle, const uint8_t* data,
size_t data_length);
UIWidgetsEngineResult __UIWidgetsEngineFlushPendingTasksNow();
UIWidgetsEngineResult UIWidgetsEngineRegisterExternalTexture(
UIWidgetsEngine engine, int64_t texture_identifier);
UIWidgetsEngineResult UIWidgetsEngineUnregisterExternalTexture(
UIWidgetsEngine engine, int64_t texture_identifier);
UIWidgetsEngineResult UIWidgetsEngineMarkExternalTextureFrameAvailable(
UIWidgetsEngine engine, int64_t texture_identifier);
UIWidgetsEngineResult UIWidgetsEngineUpdateAccessibilityFeatures(
UIWidgetsEngine engine, UIWidgetsAccessibilityFeature features);
UIWidgetsEngineResult UIWidgetsEngineOnVsync(UIWidgetsEngine engine,
intptr_t baton,
uint64_t frame_start_time_nanos,
uint64_t frame_target_time_nanos);
UIWidgetsEngineResult UIWidgetsEngineReloadSystemFonts(UIWidgetsEngine engine);
void UIWidgetsEngineTraceEventDurationBegin(const char* name);
void UIWidgetsEngineTraceEventDurationEnd(const char* name);
void UIWidgetsEngineTraceEventInstant(const char* name);
UIWidgetsEngineResult UIWidgetsEnginePostRenderThreadTask(
UIWidgetsEngine engine, VoidCallback callback, void* callback_data);
uint64_t UIWidgetsEngineGetCurrentTime();
UIWidgetsEngineResult UIWidgetsEngineRunTask(UIWidgetsEngine engine,
const UIWidgetsTask* task);
UIWidgetsEngineResult UIWidgetsEngineUpdateLocales(
UIWidgetsEngine engine, const UIWidgetsLocale** locales,
size_t locales_count);
UIWidgetsEngineResult UIWidgetsEngineNotifyLowMemoryWarning(
UIWidgetsEngine engine);
UIWidgetsEngineResult UIWidgetsEnginePostCallbackOnAllNativeThreads(
UIWidgetsEngine engine, UIWidgetsNativeThreadCallback callback,
void* user_data);
#if defined(__cplusplus)
} // extern "C"
#endif

252
engine/src/shell/platform/embedder/embedder_engine.cc


#include "embedder_engine.h"
#include <utility>
#include "flutter/fml/make_copyable.h"
#include "shell/platform/embedder/vsync_waiter_embedder.h"
namespace uiwidgets {
struct ShellArgs {
WindowData window_data;
Settings settings;
Shell::CreateCallback<PlatformView> on_create_platform_view;
Shell::CreateCallback<Rasterizer> on_create_rasterizer;
ShellArgs(const WindowData& p_window_data, const Settings& p_settings,
Shell::CreateCallback<PlatformView> p_on_create_platform_view,
Shell::CreateCallback<Rasterizer> p_on_create_rasterizer)
: window_data(p_window_data),
settings(p_settings),
on_create_platform_view(std::move(p_on_create_platform_view)),
on_create_rasterizer(std::move(p_on_create_rasterizer)) {}
};
EmbedderEngine::EmbedderEngine(
std::unique_ptr<EmbedderThreadHost> thread_host,
const TaskRunners& task_runners, const WindowData& window_data,
const Settings& settings, RunConfiguration run_configuration,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer,
EmbedderExternalTextureGL::ExternalTextureCallback
external_texture_callback)
: thread_host_(std::move(thread_host)),
task_runners_(task_runners),
run_configuration_(std::move(run_configuration)),
shell_args_(std::make_unique<ShellArgs>(
window_data, settings, std::move(on_create_platform_view),
std::move(on_create_rasterizer))),
external_texture_callback_(std::move(external_texture_callback)) {}
EmbedderEngine::~EmbedderEngine() = default;
bool EmbedderEngine::LaunchShell() {
if (!shell_args_) {
FML_DLOG(ERROR) << "Invalid shell arguments.";
return false;
}
if (shell_) {
FML_DLOG(ERROR) << "Shell already initialized";
}
shell_ = Shell::Create(
task_runners_, shell_args_->window_data, shell_args_->settings,
shell_args_->on_create_platform_view, shell_args_->on_create_rasterizer);
// Reset the args no matter what. They will never be used to initialize a
// shell again.
shell_args_.reset();
return IsValid();
}
bool EmbedderEngine::CollectShell() {
shell_.reset();
return IsValid();
}
bool EmbedderEngine::RunRootIsolate() {
if (!IsValid() || !run_configuration_.IsValid()) {
return false;
}
shell_->RunEngine(std::move(run_configuration_));
return true;
}
bool EmbedderEngine::IsValid() const { return static_cast<bool>(shell_); }
const TaskRunners& EmbedderEngine::GetTaskRunners() const {
return task_runners_;
}
bool EmbedderEngine::NotifyCreated() {
if (!IsValid()) {
return false;
}
shell_->GetPlatformView()->NotifyCreated();
return true;
}
bool EmbedderEngine::NotifyDestroyed() {
if (!IsValid()) {
return false;
}
shell_->GetPlatformView()->NotifyDestroyed();
return true;
}
bool EmbedderEngine::SetViewportMetrics(ViewportMetrics metrics) {
if (!IsValid()) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->SetViewportMetrics(std::move(metrics));
return true;
}
bool EmbedderEngine::DispatchPointerDataPacket(
std::unique_ptr<PointerDataPacket> packet) {
if (!IsValid() || !packet) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->DispatchPointerDataPacket(std::move(packet));
return true;
}
bool EmbedderEngine::SendPlatformMessage(fml::RefPtr<PlatformMessage> message) {
if (!IsValid() || !message) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->DispatchPlatformMessage(message);
return true;
}
bool EmbedderEngine::RegisterTexture(int64_t texture) {
if (!IsValid() || !external_texture_callback_) {
return false;
}
shell_->GetPlatformView()->RegisterTexture(
std::make_unique<EmbedderExternalTextureGL>(texture,
external_texture_callback_));
return true;
}
bool EmbedderEngine::UnregisterTexture(int64_t texture) {
if (!IsValid() || !external_texture_callback_) {
return false;
}
shell_->GetPlatformView()->UnregisterTexture(texture);
return true;
}
bool EmbedderEngine::MarkTextureFrameAvailable(int64_t texture) {
if (!IsValid() || !external_texture_callback_) {
return false;
}
shell_->GetPlatformView()->MarkTextureFrameAvailable(texture);
return true;
}
bool EmbedderEngine::SetAccessibilityFeatures(int32_t flags) {
if (!IsValid()) {
return false;
}
auto platform_view = shell_->GetPlatformView();
if (!platform_view) {
return false;
}
platform_view->SetAccessibilityFeatures(flags);
return true;
}
bool EmbedderEngine::OnVsyncEvent(intptr_t baton,
fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time) {
if (!IsValid()) {
return false;
}
return VsyncWaiterEmbedder::OnEmbedderVsync(baton, frame_start_time,
frame_target_time);
}
bool EmbedderEngine::ReloadSystemFonts() {
if (!IsValid()) {
return false;
}
return shell_->ReloadSystemFonts();
}
bool EmbedderEngine::PostRenderThreadTask(const fml::closure& task) {
if (!IsValid()) {
return false;
}
shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(task);
return true;
}
bool EmbedderEngine::RunTask(const UIWidgetsTask* task) {
// The shell doesn't need to be running or valid for access to the thread
// host. This is why there is no `IsValid` check here. This allows embedders
// to perform custom task runner interop before the shell is running.
if (task == nullptr) {
return false;
}
return thread_host_->PostTask(reinterpret_cast<int64_t>(task->runner),
task->task);
}
bool EmbedderEngine::PostTaskOnEngineManagedNativeThreads(
std::function<void(UIWidgetsNativeThreadType)> closure) const {
if (!IsValid() || closure == nullptr) {
return false;
}
const auto trampoline = [closure](UIWidgetsNativeThreadType type,
fml::RefPtr<fml::TaskRunner> runner) {
runner->PostTask([closure, type] { closure(type); });
};
// Post the task to all thread host threads.
const auto& task_runners = shell_->GetTaskRunners();
trampoline(kUIWidgetsNativeThreadTypeRender,
task_runners.GetRasterTaskRunner());
trampoline(kUIWidgetsNativeThreadTypeWorker, task_runners.GetIOTaskRunner());
trampoline(kUIWidgetsNativeThreadTypeUI, task_runners.GetUITaskRunner());
trampoline(kUIWidgetsNativeThreadTypePlatform,
task_runners.GetPlatformTaskRunner());
// Post the task to all worker threads.
auto engine = shell_->GetEngine();
engine->GetConcurrentMessageLoop()->PostTaskToAllWorkers(
[closure]() { closure(kUIWidgetsNativeThreadTypeWorker); });
return true;
}
Shell& EmbedderEngine::GetShell() {
FML_DCHECK(shell_);
return *shell_.get();
}
} // namespace uiwidgets

84
engine/src/shell/platform/embedder/embedder_engine.h


#pragma once
#include <memory>
#include <unordered_map>
#include "flutter/fml/macros.h"
#include "shell/common/shell.h"
#include "shell/common/thread_host.h"
#include "shell/platform/embedder/embedder.h"
#include "shell/platform/embedder/embedder_engine.h"
#include "shell/platform/embedder/embedder_external_texture_gl.h"
#include "shell/platform/embedder/embedder_thread_host.h"
namespace uiwidgets {
struct ShellArgs;
class EmbedderEngine {
public:
EmbedderEngine(std::unique_ptr<EmbedderThreadHost> thread_host,
const TaskRunners& task_runners, const WindowData& window_data, const Settings& settings,
RunConfiguration run_configuration,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer,
EmbedderExternalTextureGL::ExternalTextureCallback
external_texture_callback);
~EmbedderEngine();
bool LaunchShell();
bool CollectShell();
const TaskRunners& GetTaskRunners() const;
bool NotifyCreated();
bool NotifyDestroyed();
bool RunRootIsolate();
bool IsValid() const;
bool SetViewportMetrics(ViewportMetrics metrics);
bool DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet);
bool SendPlatformMessage(fml::RefPtr<PlatformMessage> message);
bool RegisterTexture(int64_t texture);
bool UnregisterTexture(int64_t texture);
bool MarkTextureFrameAvailable(int64_t texture);
bool SetAccessibilityFeatures(int32_t flags);
bool OnVsyncEvent(intptr_t baton, fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time);
bool ReloadSystemFonts();
bool PostRenderThreadTask(const fml::closure& task);
bool RunTask(const UIWidgetsTask* task);
bool PostTaskOnEngineManagedNativeThreads(
std::function<void(UIWidgetsNativeThreadType)> closure) const;
Shell& GetShell();
private:
const std::unique_ptr<EmbedderThreadHost> thread_host_;
TaskRunners task_runners_;
RunConfiguration run_configuration_;
std::unique_ptr<ShellArgs> shell_args_;
std::unique_ptr<Shell> shell_;
const EmbedderExternalTextureGL::ExternalTextureCallback
external_texture_callback_;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderEngine);
};
} // namespace uiwidgets

47
engine/src/shell/platform/embedder/embedder_external_texture_gl.cc


#include "embedder_external_texture_gl.h"
#include "flutter/fml/logging.h"
namespace uiwidgets {
EmbedderExternalTextureGL::EmbedderExternalTextureGL(
int64_t texture_identifier, const ExternalTextureCallback& callback)
: Texture(texture_identifier), external_texture_callback_(callback) {
FML_DCHECK(external_texture_callback_);
}
EmbedderExternalTextureGL::~EmbedderExternalTextureGL() = default;
// |flutter::Texture|
void EmbedderExternalTextureGL::Paint(SkCanvas& canvas, const SkRect& bounds,
bool freeze, GrContext* context) {
if (auto image = external_texture_callback_(
Id(), //
canvas.getGrContext(), //
SkISize::Make(bounds.width(), bounds.height()) //
)) {
last_image_ = image;
}
if (last_image_) {
if (bounds != SkRect::Make(last_image_->bounds())) {
canvas.drawImageRect(last_image_, bounds, nullptr);
} else {
canvas.drawImage(last_image_, bounds.x(), bounds.y());
}
}
}
// |flutter::Texture|
void EmbedderExternalTextureGL::OnGrContextCreated() {}
// |flutter::Texture|
void EmbedderExternalTextureGL::OnGrContextDestroyed() {}
// |flutter::Texture|
void EmbedderExternalTextureGL::MarkNewFrameAvailable() {}
// |flutter::Texture|
void EmbedderExternalTextureGL::OnTextureUnregistered() {}
} // namespace uiwidgets

43
engine/src/shell/platform/embedder/embedder_external_texture_gl.h


#pragma once
#include "flow/texture.h"
#include "flutter/fml/macros.h"
#include "include/core/SkImage.h"
#include "include/core/SkSize.h"
namespace uiwidgets {
class EmbedderExternalTextureGL : public Texture {
public:
using ExternalTextureCallback = std::function<sk_sp<SkImage>(
int64_t texture_identifier, GrContext*, const SkISize&)>;
EmbedderExternalTextureGL(int64_t texture_identifier,
const ExternalTextureCallback& callback);
~EmbedderExternalTextureGL();
private:
ExternalTextureCallback external_texture_callback_;
sk_sp<SkImage> last_image_;
// |flutter::Texture|
void Paint(SkCanvas& canvas, const SkRect& bounds, bool freeze,
GrContext* context) override;
// |flutter::Texture|
void OnGrContextCreated() override;
// |flutter::Texture|
void OnGrContextDestroyed() override;
// |flutter::Texture|
void MarkNewFrameAvailable() override;
// |flutter::Texture|
void OnTextureUnregistered() override;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderExternalTextureGL);
};
} // namespace uiwidgets

98
engine/src/shell/platform/embedder/embedder_external_view.cc


#include "embedder_external_view.h"
#include "flutter/fml/trace_event.h"
#include "shell/common/canvas_spy.h"
namespace uiwidgets {
static SkISize TransformedSurfaceSize(const SkISize& size,
const SkMatrix& transformation) {
const auto source_rect = SkRect::MakeWH(size.width(), size.height());
const auto transformed_rect = transformation.mapRect(source_rect);
return SkISize::Make(transformed_rect.width(), transformed_rect.height());
}
EmbedderExternalView::EmbedderExternalView(
const SkISize& frame_size, const SkMatrix& surface_transformation)
: EmbedderExternalView(frame_size, surface_transformation, {}, nullptr) {}
EmbedderExternalView::EmbedderExternalView(
const SkISize& frame_size, const SkMatrix& surface_transformation,
ViewIdentifier view_identifier, std::unique_ptr<EmbeddedViewParams> params)
: render_surface_size_(
TransformedSurfaceSize(frame_size, surface_transformation)),
surface_transformation_(surface_transformation),
view_identifier_(view_identifier),
embedded_view_params_(std::move(params)),
recorder_(std::make_unique<SkPictureRecorder>()),
canvas_spy_(std::make_unique<CanvasSpy>(recorder_->beginRecording(
frame_size.width(), frame_size.height()))) {}
EmbedderExternalView::~EmbedderExternalView() = default;
EmbedderExternalView::RenderTargetDescriptor
EmbedderExternalView::CreateRenderTargetDescriptor() const {
return {view_identifier_, render_surface_size_};
}
SkCanvas* EmbedderExternalView::GetCanvas() const {
return canvas_spy_->GetSpyingCanvas();
}
SkISize EmbedderExternalView::GetRenderSurfaceSize() const {
return render_surface_size_;
}
bool EmbedderExternalView::IsRootView() const { return !HasPlatformView(); }
bool EmbedderExternalView::HasPlatformView() const {
return view_identifier_.platform_view_id.has_value();
}
bool EmbedderExternalView::HasEngineRenderedContents() const {
return canvas_spy_->DidDrawIntoCanvas();
}
EmbedderExternalView::ViewIdentifier EmbedderExternalView::GetViewIdentifier()
const {
return view_identifier_;
}
const EmbeddedViewParams* EmbedderExternalView::GetEmbeddedViewParams() const {
return embedded_view_params_.get();
}
bool EmbedderExternalView::Render(const EmbedderRenderTarget& render_target) {
TRACE_EVENT0("flutter", "EmbedderExternalView::Render");
FML_DCHECK(HasEngineRenderedContents())
<< "Unnecessarily asked to render into a render target when there was "
"nothing to render.";
auto picture = recorder_->finishRecordingAsPicture();
if (!picture) {
return false;
}
auto surface = render_target.GetRenderSurface();
if (!surface) {
return false;
}
FML_DCHECK(SkISize::Make(surface->width(), surface->height()) ==
render_surface_size_);
auto canvas = surface->getCanvas();
if (!canvas) {
return false;
}
canvas->setMatrix(surface_transformation_);
canvas->clear(SK_ColorTRANSPARENT);
canvas->drawPicture(picture);
canvas->flush();
return true;
}
} // namespace uiwidgets

118
engine/src/shell/platform/embedder/embedder_external_view.h


#pragma once
#include <optional>
#include <unordered_map>
#include <unordered_set>
#include "flow/embedded_views.h"
#include "flutter/fml/hash_combine.h"
#include "flutter/fml/macros.h"
#include "include/core/SkPictureRecorder.h"
#include "shell/common/canvas_spy.h"
#include "shell/platform/embedder/embedder_render_target.h"
namespace uiwidgets {
class EmbedderExternalView {
public:
using PlatformViewID = int64_t;
struct ViewIdentifier {
std::optional<PlatformViewID> platform_view_id;
ViewIdentifier() {}
ViewIdentifier(PlatformViewID view_id) : platform_view_id(view_id) {}
struct Hash {
constexpr std::size_t operator()(const ViewIdentifier& desc) const {
if (!desc.platform_view_id.has_value()) {
return fml::HashCombine();
}
return fml::HashCombine(desc.platform_view_id.value());
}
};
struct Equal {
constexpr bool operator()(const ViewIdentifier& lhs,
const ViewIdentifier& rhs) const {
return lhs.platform_view_id == rhs.platform_view_id;
}
};
};
struct RenderTargetDescriptor {
ViewIdentifier view_identifier;
SkISize surface_size;
RenderTargetDescriptor(ViewIdentifier p_view_identifier,
SkISize p_surface_size)
: view_identifier(p_view_identifier), surface_size(p_surface_size) {}
struct Hash {
constexpr std::size_t operator()(
const RenderTargetDescriptor& desc) const {
return fml::HashCombine(desc.surface_size.width(),
desc.surface_size.height(),
ViewIdentifier::Hash{}(desc.view_identifier));
}
};
struct Equal {
bool operator()(const RenderTargetDescriptor& lhs,
const RenderTargetDescriptor& rhs) const {
return lhs.surface_size == rhs.surface_size &&
ViewIdentifier::Equal{}(lhs.view_identifier,
rhs.view_identifier);
}
};
};
using ViewIdentifierSet =
std::unordered_set<ViewIdentifier, ViewIdentifier::Hash,
ViewIdentifier::Equal>;
using PendingViews =
std::unordered_map<ViewIdentifier, std::unique_ptr<EmbedderExternalView>,
ViewIdentifier::Hash, ViewIdentifier::Equal>;
EmbedderExternalView(const SkISize& frame_size,
const SkMatrix& surface_transformation);
EmbedderExternalView(const SkISize& frame_size,
const SkMatrix& surface_transformation,
ViewIdentifier view_identifier,
std::unique_ptr<EmbeddedViewParams> params);
~EmbedderExternalView();
bool IsRootView() const;
bool HasPlatformView() const;
bool HasEngineRenderedContents() const;
ViewIdentifier GetViewIdentifier() const;
const EmbeddedViewParams* GetEmbeddedViewParams() const;
RenderTargetDescriptor CreateRenderTargetDescriptor() const;
SkCanvas* GetCanvas() const;
SkISize GetRenderSurfaceSize() const;
bool Render(const EmbedderRenderTarget& render_target);
private:
const SkISize render_surface_size_;
const SkMatrix surface_transformation_;
ViewIdentifier view_identifier_;
std::unique_ptr<EmbeddedViewParams> embedded_view_params_;
std::unique_ptr<SkPictureRecorder> recorder_;
std::unique_ptr<CanvasSpy> canvas_spy_;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderExternalView);
};
} // namespace uiwidgets

265
engine/src/shell/platform/embedder/embedder_external_view_embedder.cc


#include "embedder_external_view_embedder.h"
#include <algorithm>
#include "include/gpu/GrContext.h"
#include "shell/platform/embedder/embedder_layers.h"
#include "shell/platform/embedder/embedder_render_target.h"
namespace uiwidgets {
EmbedderExternalViewEmbedder::EmbedderExternalViewEmbedder(
const CreateRenderTargetCallback& create_render_target_callback,
const PresentCallback& present_callback)
: create_render_target_callback_(create_render_target_callback),
present_callback_(present_callback) {
FML_DCHECK(create_render_target_callback_);
FML_DCHECK(present_callback_);
}
EmbedderExternalViewEmbedder::~EmbedderExternalViewEmbedder() = default;
void EmbedderExternalViewEmbedder::SetSurfaceTransformationCallback(
SurfaceTransformationCallback surface_transformation_callback) {
surface_transformation_callback_ = surface_transformation_callback;
}
SkMatrix EmbedderExternalViewEmbedder::GetSurfaceTransformation() const {
if (!surface_transformation_callback_) {
return SkMatrix{};
}
return surface_transformation_callback_();
}
void EmbedderExternalViewEmbedder::Reset() {
pending_views_.clear();
composition_order_.clear();
}
// |ExternalViewEmbedder|
void EmbedderExternalViewEmbedder::CancelFrame() { Reset(); }
// |ExternalViewEmbedder|
void EmbedderExternalViewEmbedder::BeginFrame(SkISize frame_size,
GrContext* context,
double device_pixel_ratio) {
Reset();
pending_frame_size_ = frame_size;
pending_device_pixel_ratio_ = device_pixel_ratio;
pending_surface_transformation_ = GetSurfaceTransformation();
static const auto kRootViewIdentifier =
EmbedderExternalView::ViewIdentifier{};
pending_views_[kRootViewIdentifier] = std::make_unique<EmbedderExternalView>(
pending_frame_size_, pending_surface_transformation_);
composition_order_.push_back(kRootViewIdentifier);
}
// |ExternalViewEmbedder|
void EmbedderExternalViewEmbedder::PrerollCompositeEmbeddedView(
int view_id, std::unique_ptr<EmbeddedViewParams> params) {
FML_DCHECK(pending_views_.count(view_id) == 0);
pending_views_[view_id] = std::make_unique<EmbedderExternalView>(
pending_frame_size_, // frame size
pending_surface_transformation_, // surface xformation
view_id, // view identifier
std::move(params) // embedded view params
);
composition_order_.push_back(view_id);
}
// |ExternalViewEmbedder|
SkCanvas* EmbedderExternalViewEmbedder::GetRootCanvas() {
auto found = pending_views_.find(EmbedderExternalView::ViewIdentifier{});
if (found == pending_views_.end()) {
FML_DLOG(WARNING)
<< "No root canvas could be found. This is extremely unlikely and "
"indicates that the external view embedder did not receive the "
"notification to begin the frame.";
return nullptr;
}
return found->second->GetCanvas();
}
// |ExternalViewEmbedder|
std::vector<SkCanvas*> EmbedderExternalViewEmbedder::GetCurrentCanvases() {
std::vector<SkCanvas*> canvases;
for (const auto& view : pending_views_) {
const auto& external_view = view.second;
// This method (for legacy reasons) expects non-root current canvases.
if (!external_view->IsRootView()) {
canvases.push_back(external_view->GetCanvas());
}
}
return canvases;
}
// |ExternalViewEmbedder|
SkCanvas* EmbedderExternalViewEmbedder::CompositeEmbeddedView(int view_id) {
auto found = pending_views_.find(view_id);
if (found == pending_views_.end()) {
FML_DCHECK(false) << "Attempted to composite a view that was not "
"pre-rolled.";
return nullptr;
}
return found->second->GetCanvas();
}
static UIWidgetsBackingStoreConfig MakeBackingStoreConfig(
const SkISize& backing_store_size) {
UIWidgetsBackingStoreConfig config = {};
config.struct_size = sizeof(config);
config.size.width = backing_store_size.width();
config.size.height = backing_store_size.height();
return config;
}
// |ExternalViewEmbedder|
bool EmbedderExternalViewEmbedder::SubmitFrame(GrContext* context,
SkCanvas* background_canvas) {
auto [matched_render_targets, pending_keys] =
render_target_cache_.GetExistingTargetsInCache(pending_views_);
// This is where unused render targets will be collected. Control may flow to
// the embedder. Here, the embedder has the opportunity to trample on the
// OpenGL context.
//
// For optimum performance, we should tell the render target cache to clear
// its unused entries before allocating new ones. This collection step before
// allocating new render targets ameliorates peak memory usage within the
// frame. But, this causes an issue in a known internal embedder. To work
// around this issue while that embedder migrates, collection of render
// targets is deferred after the presentation.
//
// @warning: Embedder may trample on our OpenGL context here.
auto deferred_cleanup_render_targets =
render_target_cache_.ClearAllRenderTargetsInCache();
for (const auto& pending_key : pending_keys) {
const auto& external_view = pending_views_.at(pending_key);
// If the external view does not have engine rendered contents, it makes no
// sense to ask to embedder to create a render target for us as we don't
// intend to render into it and ask the embedder for presentation anyway.
// Save some memory.
if (!external_view->HasEngineRenderedContents()) {
continue;
}
// This is the size of render surface we want the embedder to create for
// us. As or right now, this is going to always be equal to the frame size
// post transformation. But, in case optimizations are applied that make
// it so that embedder rendered into surfaces that aren't full screen,
// this assumption will break. So it's just best to ask view for its size
// directly.
const auto render_surface_size = external_view->GetRenderSurfaceSize();
const auto backing_store_config =
MakeBackingStoreConfig(render_surface_size);
// This is where the embedder will create render targets for us. Control
// flow to the embedder makes the engine susceptible to having the embedder
// trample on the OpenGL context. Before any Skia operations are performed,
// the context must be reset.
//
// @warning: Embedder may trample on our OpenGL context here.
auto render_target =
create_render_target_callback_(context, backing_store_config);
if (!render_target) {
FML_LOG(ERROR) << "Embedder did not return a valid render target.";
return false;
}
matched_render_targets[pending_key] = std::move(render_target);
}
// The OpenGL context could have been trampled by the embedder at this point
// as it attempted to collect old render targets and create new ones. Tell
// Skia to not rely on existing bindings.
if (context) {
context->resetContext(kAll_GrBackendState);
}
// Scribble embedder provide render targets. The order in which we scribble
// into the buffers is irrelevant to the presentation order.
for (const auto& render_target : matched_render_targets) {
if (!pending_views_.at(render_target.first)
->Render(*render_target.second)) {
FML_LOG(ERROR)
<< "Could not render into the embedder supplied render target.";
return false;
}
}
// We are going to be transferring control back over to the embedder there the
// context may be trampled upon again. Flush all operations to the underlying
// rendering API.
//
// @warning: Embedder may trample on our OpenGL context here.
if (context) {
context->flush(GrFlushInfo());
}
// Submit the scribbled layer to the embedder for presentation.
//
// @warning: Embedder may trample on our OpenGL context here.
{
EmbedderLayers presented_layers(pending_frame_size_,
pending_device_pixel_ratio_,
pending_surface_transformation_);
// In composition order, submit backing stores and platform views to the
// embedder.
for (const auto& view_id : composition_order_) {
// If the external view has a platform view, ask the emebdder to place it
// before the Flutter rendered contents for that interleaving level.
const auto& external_view = pending_views_.at(view_id);
if (external_view->HasPlatformView()) {
presented_layers.PushPlatformViewLayer(
external_view->GetViewIdentifier()
.platform_view_id.value(), // view id
*external_view->GetEmbeddedViewParams() // view params
);
}
// If the view has engine rendered contents, ask the embedder to place
// Flutter rendered contents for this interleaving level on top of a
// platform view.
if (external_view->HasEngineRenderedContents()) {
const auto& exteral_render_target = matched_render_targets.at(view_id);
presented_layers.PushBackingStoreLayer(
exteral_render_target->GetBackingStore());
}
}
// Flush the layer description down to the embedder for presentation.
//
// @warning: Embedder may trample on our OpenGL context here.
presented_layers.InvokePresentCallback(present_callback_);
}
// See why this is necessary in the comment where this collection in realized.
//
// @warning: Embedder may trample on our OpenGL context here.
deferred_cleanup_render_targets.clear();
// Hold all rendered layers in the render target cache for one frame to
// see if they may be reused next frame.
for (auto& render_target : matched_render_targets) {
render_target_cache_.CacheRenderTarget(render_target.first,
std::move(render_target.second));
}
return true;
}
// |ExternalViewEmbedder|
void EmbedderExternalViewEmbedder::FinishFrame() {}
} // namespace uiwidgets

77
engine/src/shell/platform/embedder/embedder_external_view_embedder.h


#pragma once
#include <map>
#include <unordered_map>
#include "flow/embedded_views.h"
#include "flutter/fml/hash_combine.h"
#include "flutter/fml/macros.h"
#include "shell/platform/embedder/embedder_external_view.h"
#include "shell/platform/embedder/embedder_render_target_cache.h"
namespace uiwidgets {
class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder {
public:
using CreateRenderTargetCallback =
std::function<std::unique_ptr<EmbedderRenderTarget>(
GrContext* context, const UIWidgetsBackingStoreConfig& config)>;
using PresentCallback =
std::function<bool(const std::vector<const UIWidgetsLayer*>& layers)>;
using SurfaceTransformationCallback = std::function<SkMatrix(void)>;
EmbedderExternalViewEmbedder(
const CreateRenderTargetCallback& create_render_target_callback,
const PresentCallback& present_callback);
~EmbedderExternalViewEmbedder() override;
void SetSurfaceTransformationCallback(
SurfaceTransformationCallback surface_transformation_callback);
private:
// |ExternalViewEmbedder|
void CancelFrame() override;
// |ExternalViewEmbedder|
void BeginFrame(SkISize frame_size, GrContext* context,
double device_pixel_ratio) override;
// |ExternalViewEmbedder|
void PrerollCompositeEmbeddedView(
int view_id, std::unique_ptr<EmbeddedViewParams> params) override;
// |ExternalViewEmbedder|
std::vector<SkCanvas*> GetCurrentCanvases() override;
// |ExternalViewEmbedder|
SkCanvas* CompositeEmbeddedView(int view_id) override;
// |ExternalViewEmbedder|
bool SubmitFrame(GrContext* context, SkCanvas* background_canvas) override;
// |ExternalViewEmbedder|
void FinishFrame() override;
// |ExternalViewEmbedder|
SkCanvas* GetRootCanvas() override;
private:
const CreateRenderTargetCallback create_render_target_callback_;
const PresentCallback present_callback_;
SurfaceTransformationCallback surface_transformation_callback_;
SkISize pending_frame_size_ = SkISize::Make(0, 0);
double pending_device_pixel_ratio_ = 1.0;
SkMatrix pending_surface_transformation_;
EmbedderExternalView::PendingViews pending_views_;
std::vector<EmbedderExternalView::ViewIdentifier> composition_order_;
EmbedderRenderTargetCache render_target_cache_;
void Reset();
SkMatrix GetSurfaceTransformation() const;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderExternalViewEmbedder);
};
} // namespace uiwidgets

205
engine/src/shell/platform/embedder/embedder_layers.cc


#include "embedder_layers.h"
#include <algorithm>
namespace uiwidgets {
EmbedderLayers::EmbedderLayers(SkISize frame_size, double device_pixel_ratio,
SkMatrix root_surface_transformation)
: frame_size_(frame_size),
device_pixel_ratio_(device_pixel_ratio),
root_surface_transformation_(root_surface_transformation) {}
EmbedderLayers::~EmbedderLayers() = default;
void EmbedderLayers::PushBackingStoreLayer(const UIWidgetsBackingStore* store) {
UIWidgetsLayer layer = {};
layer.struct_size = sizeof(UIWidgetsLayer);
layer.type = kUIWidgetsLayerContentTypeBackingStore;
layer.backing_store = store;
const auto layer_bounds =
SkRect::MakeWH(frame_size_.width(), frame_size_.height());
const auto transformed_layer_bounds =
root_surface_transformation_.mapRect(layer_bounds);
layer.offset.x = transformed_layer_bounds.x();
layer.offset.y = transformed_layer_bounds.y();
layer.size.width = transformed_layer_bounds.width();
layer.size.height = transformed_layer_bounds.height();
presented_layers_.push_back(layer);
}
static std::unique_ptr<UIWidgetsPlatformViewMutation> ConvertMutation(
double opacity) {
UIWidgetsPlatformViewMutation mutation = {};
mutation.type = kUIWidgetsPlatformViewMutationTypeOpacity;
mutation.opacity = opacity;
return std::make_unique<UIWidgetsPlatformViewMutation>(mutation);
}
static std::unique_ptr<UIWidgetsPlatformViewMutation> ConvertMutation(
const SkRect& rect) {
UIWidgetsPlatformViewMutation mutation = {};
mutation.type = kUIWidgetsPlatformViewMutationTypeClipRect;
mutation.clip_rect.left = rect.left();
mutation.clip_rect.top = rect.top();
mutation.clip_rect.right = rect.right();
mutation.clip_rect.bottom = rect.bottom();
return std::make_unique<UIWidgetsPlatformViewMutation>(mutation);
}
static UIWidgetsSize VectorToSize(const SkVector& vector) {
UIWidgetsSize size = {};
size.width = vector.x();
size.height = vector.y();
return size;
}
static std::unique_ptr<UIWidgetsPlatformViewMutation> ConvertMutation(
const SkRRect& rrect) {
UIWidgetsPlatformViewMutation mutation = {};
mutation.type = kUIWidgetsPlatformViewMutationTypeClipRoundedRect;
const auto& rect = rrect.rect();
mutation.clip_rounded_rect.rect.left = rect.left();
mutation.clip_rounded_rect.rect.top = rect.top();
mutation.clip_rounded_rect.rect.right = rect.right();
mutation.clip_rounded_rect.rect.bottom = rect.bottom();
mutation.clip_rounded_rect.upper_left_corner_radius =
VectorToSize(rrect.radii(SkRRect::Corner::kUpperLeft_Corner));
mutation.clip_rounded_rect.upper_right_corner_radius =
VectorToSize(rrect.radii(SkRRect::Corner::kUpperRight_Corner));
mutation.clip_rounded_rect.lower_right_corner_radius =
VectorToSize(rrect.radii(SkRRect::Corner::kLowerRight_Corner));
mutation.clip_rounded_rect.lower_left_corner_radius =
VectorToSize(rrect.radii(SkRRect::Corner::kLowerLeft_Corner));
return std::make_unique<UIWidgetsPlatformViewMutation>(mutation);
}
static std::unique_ptr<UIWidgetsPlatformViewMutation> ConvertMutation(
const SkMatrix& matrix) {
UIWidgetsPlatformViewMutation mutation = {};
mutation.type = kUIWidgetsPlatformViewMutationTypeTransformation;
mutation.transformation.scaleX = matrix[SkMatrix::kMScaleX];
mutation.transformation.skewX = matrix[SkMatrix::kMSkewX];
mutation.transformation.transX = matrix[SkMatrix::kMTransX];
mutation.transformation.skewY = matrix[SkMatrix::kMSkewY];
mutation.transformation.scaleY = matrix[SkMatrix::kMScaleY];
mutation.transformation.transY = matrix[SkMatrix::kMTransY];
mutation.transformation.pers0 = matrix[SkMatrix::kMPersp0];
mutation.transformation.pers1 = matrix[SkMatrix::kMPersp1];
mutation.transformation.pers2 = matrix[SkMatrix::kMPersp2];
return std::make_unique<UIWidgetsPlatformViewMutation>(mutation);
}
void EmbedderLayers::PushPlatformViewLayer(
UIWidgetsPlatformViewIdentifier identifier,
const EmbeddedViewParams& params) {
{
UIWidgetsPlatformView view = {};
view.struct_size = sizeof(UIWidgetsPlatformView);
view.identifier = identifier;
const auto& mutators = params.mutatorsStack;
std::vector<const UIWidgetsPlatformViewMutation*> mutations_array;
for (auto i = mutators.Bottom(); i != mutators.Top(); ++i) {
const auto& mutator = *i;
switch (mutator->GetType()) {
case MutatorType::clip_rect: {
mutations_array.push_back(
mutations_referenced_
.emplace_back(ConvertMutation(mutator->GetRect()))
.get());
} break;
case MutatorType::clip_rrect: {
mutations_array.push_back(
mutations_referenced_
.emplace_back(ConvertMutation(mutator->GetRRect()))
.get());
} break;
case MutatorType::clip_path: {
// Unsupported mutation.
} break;
case MutatorType::transform: {
const auto& matrix = mutator->GetMatrix();
if (!matrix.isIdentity()) {
mutations_array.push_back(
mutations_referenced_.emplace_back(ConvertMutation(matrix))
.get());
}
} break;
case MutatorType::opacity: {
const double opacity =
std::clamp(mutator->GetAlphaFloat(), 0.0f, 1.0f);
if (opacity < 1.0) {
mutations_array.push_back(
mutations_referenced_.emplace_back(ConvertMutation(opacity))
.get());
}
} break;
}
}
if (!mutations_array.empty()) {
// If there are going to be any mutations, they must first take into
// account the root surface transformation.
if (!root_surface_transformation_.isIdentity()) {
mutations_array.push_back(
mutations_referenced_
.emplace_back(ConvertMutation(root_surface_transformation_))
.get());
}
auto mutations =
std::make_unique<std::vector<const UIWidgetsPlatformViewMutation*>>(
mutations_array.rbegin(), mutations_array.rend());
mutations_arrays_referenced_.emplace_back(std::move(mutations));
view.mutations_count = mutations_array.size();
view.mutations = mutations_arrays_referenced_.back().get()->data();
}
platform_views_referenced_.emplace_back(
std::make_unique<UIWidgetsPlatformView>(view));
}
UIWidgetsLayer layer = {};
layer.struct_size = sizeof(UIWidgetsLayer);
layer.type = kUIWidgetsLayerContentTypePlatformView;
layer.platform_view = platform_views_referenced_.back().get();
const auto layer_bounds =
SkRect::MakeXYWH(params.offsetPixels.x(), //
params.offsetPixels.y(), //
params.sizePoints.width() * device_pixel_ratio_, //
params.sizePoints.height() * device_pixel_ratio_ //
);
const auto transformed_layer_bounds =
root_surface_transformation_.mapRect(layer_bounds);
layer.offset.x = transformed_layer_bounds.x();
layer.offset.y = transformed_layer_bounds.y();
layer.size.width = transformed_layer_bounds.width();
layer.size.height = transformed_layer_bounds.height();
presented_layers_.push_back(layer);
}
void EmbedderLayers::InvokePresentCallback(
const PresentCallback& callback) const {
std::vector<const UIWidgetsLayer*> presented_layers_pointers;
presented_layers_pointers.reserve(presented_layers_.size());
for (const auto& layer : presented_layers_) {
presented_layers_pointers.push_back(&layer);
}
callback(std::move(presented_layers_pointers));
}
} // namespace uiwidgets

46
engine/src/shell/platform/embedder/embedder_layers.h


#pragma once
#include <memory>
#include <vector>
#include "flow/embedded_views.h"
#include "flutter/fml/macros.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkSize.h"
#include "shell/platform/embedder/embedder.h"
namespace uiwidgets {
class EmbedderLayers {
public:
EmbedderLayers(SkISize frame_size, double device_pixel_ratio,
SkMatrix root_surface_transformation);
~EmbedderLayers();
void PushBackingStoreLayer(const UIWidgetsBackingStore* store);
void PushPlatformViewLayer(UIWidgetsPlatformViewIdentifier identifier,
const EmbeddedViewParams& params);
using PresentCallback =
std::function<bool(const std::vector<const UIWidgetsLayer*>& layers)>;
void InvokePresentCallback(const PresentCallback& callback) const;
private:
const SkISize frame_size_;
const double device_pixel_ratio_;
const SkMatrix root_surface_transformation_;
std::vector<std::unique_ptr<UIWidgetsPlatformView>>
platform_views_referenced_;
std::vector<std::unique_ptr<UIWidgetsPlatformViewMutation>>
mutations_referenced_;
std::vector<
std::unique_ptr<std::vector<const UIWidgetsPlatformViewMutation*>>>
mutations_arrays_referenced_;
std::vector<UIWidgetsLayer> presented_layers_;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderLayers);
};
} // namespace uiwidgets

32
engine/src/shell/platform/embedder/embedder_platform_message_response.cc


#include "embedder_platform_message_response.h"
#include "flutter/fml/make_copyable.h"
namespace uiwidgets {
EmbedderPlatformMessageResponse::EmbedderPlatformMessageResponse(
fml::RefPtr<fml::TaskRunner> runner, const Callback& callback)
: runner_(std::move(runner)), callback_(callback) {}
EmbedderPlatformMessageResponse::~EmbedderPlatformMessageResponse() = default;
// |PlatformMessageResponse|
void EmbedderPlatformMessageResponse::Complete(
std::unique_ptr<fml::Mapping> data) {
if (!data) {
CompleteEmpty();
return;
}
runner_->PostTask(
fml::MakeCopyable([data = std::move(data), callback = callback_]() {
callback(data->GetMapping(), data->GetSize());
}));
}
// |PlatformMessageResponse|
void EmbedderPlatformMessageResponse::CompleteEmpty() {
Complete(std::make_unique<fml::NonOwnedMapping>(nullptr, 0u));
}
} // namespace uiwidgets

31
engine/src/shell/platform/embedder/embedder_platform_message_response.h


#pragma once
#include "flutter/fml/macros.h"
#include "flutter/fml/task_runner.h"
#include "lib/ui/window/platform_message_response.h"
namespace uiwidgets {
class EmbedderPlatformMessageResponse : public PlatformMessageResponse {
public:
using Callback = std::function<void(const uint8_t* data, size_t size)>;
EmbedderPlatformMessageResponse(fml::RefPtr<fml::TaskRunner> runner,
const Callback& callback);
~EmbedderPlatformMessageResponse() override;
private:
fml::RefPtr<fml::TaskRunner> runner_;
Callback callback_;
// |PlatformMessageResponse|
void Complete(std::unique_ptr<fml::Mapping> data) override;
// |PlatformMessageResponse|
void CompleteEmpty() override;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderPlatformMessageResponse);
};
} // namespace uiwidgets

35
engine/src/shell/platform/embedder/embedder_render_target.cc


#pragma once
#include "embedder_render_target.h"
#include "flutter/fml/logging.h"
namespace uiwidgets {
EmbedderRenderTarget::EmbedderRenderTarget(UIWidgetsBackingStore backing_store,
sk_sp<SkSurface> render_surface,
fml::closure on_release)
: backing_store_(backing_store),
render_surface_(std::move(render_surface)),
on_release_(on_release) {
// TODO(38468): The optimization to elide backing store updates between frames
// has not been implemented yet.
backing_store_.did_update = true;
FML_DCHECK(render_surface_);
}
EmbedderRenderTarget::~EmbedderRenderTarget() {
if (on_release_) {
on_release_();
}
}
const UIWidgetsBackingStore* EmbedderRenderTarget::GetBackingStore() const {
return &backing_store_;
}
sk_sp<SkSurface> EmbedderRenderTarget::GetRenderSurface() const {
return render_surface_;
}
} // namespace uiwidgets

30
engine/src/shell/platform/embedder/embedder_render_target.h


#pragma once
#include "flutter/fml/closure.h"
#include "flutter/fml/macros.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkSurface.h"
#include "shell/platform/embedder/embedder.h"
namespace uiwidgets {
class EmbedderRenderTarget {
public:
EmbedderRenderTarget(UIWidgetsBackingStore backing_store,
sk_sp<SkSurface> render_surface,
fml::closure on_release);
~EmbedderRenderTarget();
sk_sp<SkSurface> GetRenderSurface() const;
const UIWidgetsBackingStore* GetBackingStore() const;
private:
UIWidgetsBackingStore backing_store_;
sk_sp<SkSurface> render_surface_;
fml::closure on_release_;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderRenderTarget);
};
} // namespace uiwidgets

69
engine/src/shell/platform/embedder/embedder_render_target_cache.cc


#include "embedder_render_target_cache.h"
namespace uiwidgets {
EmbedderRenderTargetCache::EmbedderRenderTargetCache() = default;
EmbedderRenderTargetCache::~EmbedderRenderTargetCache() = default;
std::pair<EmbedderRenderTargetCache::RenderTargets,
EmbedderExternalView::ViewIdentifierSet>
EmbedderRenderTargetCache::GetExistingTargetsInCache(
const EmbedderExternalView::PendingViews& pending_views) {
RenderTargets resolved_render_targets;
EmbedderExternalView::ViewIdentifierSet unmatched_identifiers;
for (const auto& view : pending_views) {
const auto& external_view = view.second;
if (!external_view->HasEngineRenderedContents()) {
continue;
}
auto& compatible_targets =
cached_render_targets_[external_view->CreateRenderTargetDescriptor()];
if (compatible_targets.size() == 0) {
unmatched_identifiers.insert(view.first);
} else {
std::unique_ptr<EmbedderRenderTarget> target =
std::move(compatible_targets.top());
compatible_targets.pop();
resolved_render_targets[view.first] = std::move(target);
}
}
return {std::move(resolved_render_targets), std::move(unmatched_identifiers)};
}
std::set<std::unique_ptr<EmbedderRenderTarget>>
EmbedderRenderTargetCache::ClearAllRenderTargetsInCache() {
std::set<std::unique_ptr<EmbedderRenderTarget>> cleared_targets;
for (auto& targets : cached_render_targets_) {
auto& targets_stack = targets.second;
while (!targets_stack.empty()) {
cleared_targets.emplace(std::move(targets_stack.top()));
targets_stack.pop();
}
}
cached_render_targets_.clear();
return cleared_targets;
}
void EmbedderRenderTargetCache::CacheRenderTarget(
EmbedderExternalView::ViewIdentifier view_identifier,
std::unique_ptr<EmbedderRenderTarget> target) {
if (target == nullptr) {
return;
}
auto surface = target->GetRenderSurface();
auto desc = EmbedderExternalView::RenderTargetDescriptor{
view_identifier, SkISize::Make(surface->width(), surface->height())};
cached_render_targets_[desc].push(std::move(target));
}
size_t EmbedderRenderTargetCache::GetCachedTargetsCount() const {
size_t count = 0;
for (const auto& targets : cached_render_targets_) {
count += targets.second.size();
}
return count;
}
} // namespace uiwidgets

49
engine/src/shell/platform/embedder/embedder_render_target_cache.h


#pragma once
#include <set>
#include <stack>
#include <tuple>
#include <unordered_map>
#include "flutter/fml/macros.h"
#include "shell/platform/embedder/embedder_external_view.h"
namespace uiwidgets {
class EmbedderRenderTargetCache {
public:
EmbedderRenderTargetCache();
~EmbedderRenderTargetCache();
using RenderTargets =
std::unordered_map<EmbedderExternalView::ViewIdentifier,
std::unique_ptr<EmbedderRenderTarget>,
EmbedderExternalView::ViewIdentifier::Hash,
EmbedderExternalView::ViewIdentifier::Equal>;
std::pair<RenderTargets, EmbedderExternalView::ViewIdentifierSet>
GetExistingTargetsInCache(
const EmbedderExternalView::PendingViews& pending_views);
std::set<std::unique_ptr<EmbedderRenderTarget>>
ClearAllRenderTargetsInCache();
void CacheRenderTarget(EmbedderExternalView::ViewIdentifier view_identifier,
std::unique_ptr<EmbedderRenderTarget> target);
size_t GetCachedTargetsCount() const;
private:
using CachedRenderTargets =
std::unordered_map<EmbedderExternalView::RenderTargetDescriptor,
std::stack<std::unique_ptr<EmbedderRenderTarget>>,
EmbedderExternalView::RenderTargetDescriptor::Hash,
EmbedderExternalView::RenderTargetDescriptor::Equal>;
CachedRenderTargets cached_render_targets_;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderRenderTargetCache);
};
} // namespace uiwidgets

9
engine/src/shell/platform/embedder/embedder_surface.cc


#include "embedder_surface.h"
namespace uiwidgets {
EmbedderSurface::EmbedderSurface() = default;
EmbedderSurface::~EmbedderSurface() = default;
} // namespace uiwidgets

25
engine/src/shell/platform/embedder/embedder_surface.h


#pragma once
#include "flow/embedded_views.h"
#include "flutter/fml/macros.h"
#include "shell/common/surface.h"
namespace uiwidgets {
class EmbedderSurface {
public:
EmbedderSurface();
virtual ~EmbedderSurface();
virtual bool IsValid() const = 0;
virtual std::unique_ptr<Surface> CreateGPUSurface() = 0;
virtual sk_sp<GrContext> CreateResourceContext() const = 0;
private:
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurface);
};
} // namespace uiwidgets

107
engine/src/shell/platform/embedder/embedder_surface_gl.cc


#include "embedder_surface_gl.h"
#include "shell/common/shell_io_manager.h"
namespace uiwidgets {
EmbedderSurfaceGL::EmbedderSurfaceGL(
GLDispatchTable gl_dispatch_table, bool fbo_reset_after_present,
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder)
: gl_dispatch_table_(gl_dispatch_table),
fbo_reset_after_present_(fbo_reset_after_present),
external_view_embedder_(std::move(external_view_embedder)) {
// Make sure all required members of the dispatch table are checked.
if (!gl_dispatch_table_.gl_make_current_callback ||
!gl_dispatch_table_.gl_clear_current_callback ||
!gl_dispatch_table_.gl_present_callback ||
!gl_dispatch_table_.gl_fbo_callback) {
return;
}
valid_ = true;
}
EmbedderSurfaceGL::~EmbedderSurfaceGL() = default;
// |EmbedderSurface|
bool EmbedderSurfaceGL::IsValid() const { return valid_; }
// |GPUSurfaceGLDelegate|
bool EmbedderSurfaceGL::GLContextMakeCurrent() {
return gl_dispatch_table_.gl_make_current_callback();
}
// |GPUSurfaceGLDelegate|
bool EmbedderSurfaceGL::GLContextClearCurrent() {
return gl_dispatch_table_.gl_clear_current_callback();
}
// |GPUSurfaceGLDelegate|
bool EmbedderSurfaceGL::GLContextPresent() {
return gl_dispatch_table_.gl_present_callback();
}
// |GPUSurfaceGLDelegate|
intptr_t EmbedderSurfaceGL::GLContextFBO() const {
return gl_dispatch_table_.gl_fbo_callback();
}
// |GPUSurfaceGLDelegate|
bool EmbedderSurfaceGL::GLContextFBOResetAfterPresent() const {
return fbo_reset_after_present_;
}
// |GPUSurfaceGLDelegate|
SkMatrix EmbedderSurfaceGL::GLContextSurfaceTransformation() const {
auto callback = gl_dispatch_table_.gl_surface_transformation_callback;
if (!callback) {
SkMatrix matrix;
matrix.setIdentity();
return matrix;
}
return callback();
}
// |GPUSurfaceGLDelegate|
ExternalViewEmbedder* EmbedderSurfaceGL::GetExternalViewEmbedder() {
return external_view_embedder_.get();
}
// |GPUSurfaceGLDelegate|
EmbedderSurfaceGL::GLProcResolver EmbedderSurfaceGL::GetGLProcResolver() const {
return gl_dispatch_table_.gl_proc_resolver;
}
// |EmbedderSurface|
std::unique_ptr<Surface> EmbedderSurfaceGL::CreateGPUSurface() {
const bool render_to_surface = !external_view_embedder_;
return std::make_unique<GPUSurfaceGL>(this, // GPU surface GL delegate
render_to_surface // render to surface
);
}
// |EmbedderSurface|
sk_sp<GrContext> EmbedderSurfaceGL::CreateResourceContext() const {
auto callback = gl_dispatch_table_.gl_make_resource_current_callback;
if (callback && callback()) {
if (auto context = ShellIOManager::CreateCompatibleResourceLoadingContext(
GrBackend::kOpenGL_GrBackend, GetGLInterface())) {
return context;
} else {
FML_LOG(ERROR)
<< "Internal error: Resource context available but could not create "
"a compatible Skia context.";
return nullptr;
}
}
// The callback was not available or failed.
FML_LOG(ERROR)
<< "Could not create a resource context for async texture uploads. "
"Expect degraded performance. Set a valid make_resource_current "
"callback on FlutterOpenGLRendererConfig.";
return nullptr;
}
} // namespace uiwidgets

73
engine/src/shell/platform/embedder/embedder_surface_gl.h


#pragma once
#include "flutter/fml/macros.h"
#include "shell/gpu/gpu_surface_gl.h"
#include "shell/platform/embedder/embedder_external_view_embedder.h"
#include "shell/platform/embedder/embedder_surface.h"
namespace uiwidgets {
class EmbedderSurfaceGL final : public EmbedderSurface,
public GPUSurfaceGLDelegate {
public:
struct GLDispatchTable {
std::function<bool(void)> gl_make_current_callback; // required
std::function<bool(void)> gl_clear_current_callback; // required
std::function<bool(void)> gl_present_callback; // required
std::function<intptr_t(void)> gl_fbo_callback; // required
std::function<bool(void)> gl_make_resource_current_callback; // optional
std::function<SkMatrix(void)>
gl_surface_transformation_callback; // optional
std::function<void*(const char*)> gl_proc_resolver; // optional
};
EmbedderSurfaceGL(
GLDispatchTable gl_dispatch_table, bool fbo_reset_after_present,
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder);
~EmbedderSurfaceGL() override;
private:
bool valid_ = false;
GLDispatchTable gl_dispatch_table_;
bool fbo_reset_after_present_;
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder_;
// |EmbedderSurface|
bool IsValid() const override;
// |EmbedderSurface|
std::unique_ptr<Surface> CreateGPUSurface() override;
// |EmbedderSurface|
sk_sp<GrContext> CreateResourceContext() const override;
// |GPUSurfaceGLDelegate|
bool GLContextMakeCurrent() override;
// |GPUSurfaceGLDelegate|
bool GLContextClearCurrent() override;
// |GPUSurfaceGLDelegate|
bool GLContextPresent() override;
// |GPUSurfaceGLDelegate|
intptr_t GLContextFBO() const override;
// |GPUSurfaceGLDelegate|
bool GLContextFBOResetAfterPresent() const override;
// |GPUSurfaceGLDelegate|
SkMatrix GLContextSurfaceTransformation() const override;
// |GPUSurfaceGLDelegate|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
// |GPUSurfaceGLDelegate|
GLProcResolver GetGLProcResolver() const override;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurfaceGL);
};
} // namespace uiwidgets

110
engine/src/shell/platform/embedder/embedder_surface_software.cc


#pragma once
#include "embedder_surface_software.h"
#include "flutter/fml/trace_event.h"
#include "include/gpu/GrContext.h"
namespace uiwidgets {
EmbedderSurfaceSoftware::EmbedderSurfaceSoftware(
SoftwareDispatchTable software_dispatch_table,
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder)
: software_dispatch_table_(software_dispatch_table),
external_view_embedder_(std::move(external_view_embedder)) {
if (!software_dispatch_table_.software_present_backing_store) {
return;
}
valid_ = true;
}
EmbedderSurfaceSoftware::~EmbedderSurfaceSoftware() = default;
// |EmbedderSurface|
bool EmbedderSurfaceSoftware::IsValid() const { return valid_; }
// |EmbedderSurface|
std::unique_ptr<Surface> EmbedderSurfaceSoftware::CreateGPUSurface() {
if (!IsValid()) {
return nullptr;
}
const bool render_to_surface = !external_view_embedder_;
auto surface = std::make_unique<GPUSurfaceSoftware>(this, render_to_surface);
if (!surface->IsValid()) {
return nullptr;
}
return surface;
}
// |EmbedderSurface|
sk_sp<GrContext> EmbedderSurfaceSoftware::CreateResourceContext() const {
return nullptr;
}
// |GPUSurfaceSoftwareDelegate|
sk_sp<SkSurface> EmbedderSurfaceSoftware::AcquireBackingStore(
const SkISize& size) {
TRACE_EVENT0("flutter", "EmbedderSurfaceSoftware::AcquireBackingStore");
if (!IsValid()) {
FML_LOG(ERROR)
<< "Could not acquire backing store for the software surface.";
return nullptr;
}
if (sk_surface_ != nullptr &&
SkISize::Make(sk_surface_->width(), sk_surface_->height()) == size) {
// The old and new surface sizes are the same. Nothing to do here.
return sk_surface_;
}
SkImageInfo info = SkImageInfo::MakeN32(
size.fWidth, size.fHeight, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
sk_surface_ = SkSurface::MakeRaster(info, nullptr);
if (sk_surface_ == nullptr) {
FML_LOG(ERROR) << "Could not create backing store for software rendering.";
return nullptr;
}
return sk_surface_;
}
// |GPUSurfaceSoftwareDelegate|
bool EmbedderSurfaceSoftware::PresentBackingStore(
sk_sp<SkSurface> backing_store) {
if (!IsValid()) {
FML_LOG(ERROR) << "Tried to present an invalid software surface.";
return false;
}
SkPixmap pixmap;
if (!backing_store->peekPixels(&pixmap)) {
FML_LOG(ERROR) << "Could not peek the pixels of the backing store.";
return false;
}
// Some basic sanity checking.
uint64_t expected_pixmap_data_size = pixmap.width() * pixmap.height() * 4;
const size_t pixmap_size = pixmap.computeByteSize();
if (expected_pixmap_data_size != pixmap_size) {
FML_LOG(ERROR) << "Software backing store had unexpected size.";
return false;
}
return software_dispatch_table_.software_present_backing_store(
pixmap.addr(), //
pixmap.rowBytes(), //
pixmap.height() //
);
}
// |GPUSurfaceSoftwareDelegate|
ExternalViewEmbedder* EmbedderSurfaceSoftware::GetExternalViewEmbedder() {
return external_view_embedder_.get();
}
} // namespace uiwidgets

51
engine/src/shell/platform/embedder/embedder_surface_software.h


#pragma once
#include "flutter/fml/macros.h"
#include "shell/gpu/gpu_surface_software.h"
#include "shell/platform/embedder/embedder_external_view_embedder.h"
#include "shell/platform/embedder/embedder_surface.h"
namespace uiwidgets {
class EmbedderSurfaceSoftware final : public EmbedderSurface,
public GPUSurfaceSoftwareDelegate {
public:
struct SoftwareDispatchTable {
std::function<bool(const void* allocation, size_t row_bytes, size_t height)>
software_present_backing_store; // required
};
EmbedderSurfaceSoftware(
SoftwareDispatchTable software_dispatch_table,
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder);
~EmbedderSurfaceSoftware() override;
private:
bool valid_ = false;
SoftwareDispatchTable software_dispatch_table_;
sk_sp<SkSurface> sk_surface_;
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder_;
// |EmbedderSurface|
bool IsValid() const override;
// |EmbedderSurface|
std::unique_ptr<Surface> CreateGPUSurface() override;
// |EmbedderSurface|
sk_sp<GrContext> CreateResourceContext() const override;
// |GPUSurfaceSoftwareDelegate|
sk_sp<SkSurface> AcquireBackingStore(const SkISize& size) override;
// |GPUSurfaceSoftwareDelegate|
bool PresentBackingStore(sk_sp<SkSurface> backing_store) override;
// |GPUSurfaceSoftwareDelegate|
ExternalViewEmbedder* GetExternalViewEmbedder() override;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurfaceSoftware);
};
} // namespace uiwidgets

82
engine/src/shell/platform/embedder/embedder_task_runner.cc


#include "embedder_task_runner.h"
#include "flutter/fml/message_loop_impl.h"
#include "flutter/fml/message_loop_task_queues.h"
namespace uiwidgets {
EmbedderTaskRunner::EmbedderTaskRunner(DispatchTable table,
size_t embedder_identifier)
: TaskRunner(nullptr /* loop implemenation*/),
embedder_identifier_(embedder_identifier),
dispatch_table_(std::move(table)),
placeholder_id_(
fml::MessageLoopTaskQueues::GetInstance()->CreateTaskQueue()) {
FML_DCHECK(dispatch_table_.post_task_callback);
FML_DCHECK(dispatch_table_.runs_task_on_current_thread_callback);
}
EmbedderTaskRunner::~EmbedderTaskRunner() = default;
size_t EmbedderTaskRunner::GetEmbedderIdentifier() const {
return embedder_identifier_;
}
void EmbedderTaskRunner::PostTask(const fml::closure& task) {
PostTaskForTime(task, fml::TimePoint::Now());
}
void EmbedderTaskRunner::PostTaskForTime(const fml::closure& task,
fml::TimePoint target_time) {
if (!task) {
return;
}
uint64_t baton = 0;
{
// Release the lock before the jump via the dispatch table.
std::scoped_lock lock(tasks_mutex_);
baton = ++last_baton_;
pending_tasks_[baton] = task;
}
dispatch_table_.post_task_callback(this, baton, target_time);
}
void EmbedderTaskRunner::PostDelayedTask(const fml::closure& task,
fml::TimeDelta delay) {
PostTaskForTime(task, fml::TimePoint::Now() + delay);
}
bool EmbedderTaskRunner::RunsTasksOnCurrentThread() {
return dispatch_table_.runs_task_on_current_thread_callback();
}
bool EmbedderTaskRunner::PostTask(uint64_t baton) {
fml::closure task;
{
std::scoped_lock lock(tasks_mutex_);
auto found = pending_tasks_.find(baton);
if (found == pending_tasks_.end()) {
FML_LOG(ERROR) << "Embedder attempted to post an unknown task.";
return false;
}
task = found->second;
pending_tasks_.erase(found);
// Let go of the tasks mutex before executing the task.
}
FML_DCHECK(task);
task();
return true;
}
// |fml::TaskRunner|
fml::TaskQueueId EmbedderTaskRunner::GetTaskQueueId() {
return placeholder_id_;
}
} // namespace uiwidgets

51
engine/src/shell/platform/embedder/embedder_task_runner.h


#pragma once
#include <mutex>
#include <unordered_map>
#include "flutter/fml/macros.h"
#include "flutter/fml/task_runner.h"
namespace uiwidgets {
class EmbedderTaskRunner final : public fml::TaskRunner {
public:
struct DispatchTable {
std::function<void(EmbedderTaskRunner* task_runner, uint64_t task_baton,
fml::TimePoint target_time)>
post_task_callback;
std::function<bool(void)> runs_task_on_current_thread_callback;
};
EmbedderTaskRunner(DispatchTable table, size_t embedder_identifier);
~EmbedderTaskRunner() override;
size_t GetEmbedderIdentifier() const;
bool PostTask(uint64_t baton);
private:
const size_t embedder_identifier_;
DispatchTable dispatch_table_;
std::mutex tasks_mutex_;
uint64_t last_baton_;
std::unordered_map<uint64_t, fml::closure> pending_tasks_;
fml::TaskQueueId placeholder_id_;
void PostTask(const fml::closure& task) override;
void PostTaskForTime(const fml::closure& task,
fml::TimePoint target_time) override;
void PostDelayedTask(const fml::closure& task, fml::TimeDelta delay) override;
bool RunsTasksOnCurrentThread() override;
fml::TaskQueueId GetTaskQueueId() override;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderTaskRunner);
};
} // namespace uiwidgets

206
engine/src/shell/platform/embedder/embedder_thread_host.cc


#define FML_USED_ON_EMBEDDER
#include "embedder_thread_host.h"
#include <algorithm>
#include "flutter/fml/message_loop.h"
namespace uiwidgets {
static std::pair<bool, fml::RefPtr<EmbedderTaskRunner>>
CreateEmbedderTaskRunner(const UIWidgetsTaskRunnerDescription* description) {
if (description == nullptr) {
// This is not embedder error. The embedder API will just have to create a
// plain old task runner (and create a thread for it) instead of using a
// task runner provided to us by the embedder.
return {true, {}};
}
if (description->runs_task_on_current_thread_callback == nullptr) {
FML_LOG(ERROR) << "UIWidgetsTaskRunnerDescription.runs_task_on_current_"
"thread_callback was nullptr.";
return {false, {}};
}
if (description->post_task_callback == nullptr) {
FML_LOG(ERROR)
<< "UIWidgetsTaskRunnerDescription.post_task_callback was nullptr.";
return {false, {}};
}
auto user_data = description->user_data;
auto post_task_callback_c = description->post_task_callback;
auto runs_task_on_current_thread_callback_c =
description->runs_task_on_current_thread_callback;
EmbedderTaskRunner::DispatchTable task_runner_dispatch_table = {
// .post_task_callback
[post_task_callback_c, user_data](EmbedderTaskRunner* task_runner,
uint64_t task_baton,
fml::TimePoint target_time) -> void {
UIWidgetsTask task = {
// runner
reinterpret_cast<UIWidgetsTaskRunner>(task_runner),
// task
task_baton,
};
post_task_callback_c(task, target_time.ToEpochDelta().ToNanoseconds(),
user_data);
},
// runs_task_on_current_thread_callback
[runs_task_on_current_thread_callback_c, user_data]() -> bool {
return runs_task_on_current_thread_callback_c(user_data);
}};
return {true, fml::MakeRefCounted<EmbedderTaskRunner>(
task_runner_dispatch_table, description->identifier)};
}
static fml::RefPtr<fml::TaskRunner> GetCurrentThreadTaskRunner() {
fml::MessageLoop::EnsureInitializedForCurrentThread();
return fml::MessageLoop::GetCurrent().GetTaskRunner();
}
constexpr const char* kUIWidgetsThreadName = "io.uiwidgets";
// static
std::unique_ptr<EmbedderThreadHost>
EmbedderThreadHost::CreateEmbedderManagedThreadHost(
const UIWidgetsCustomTaskRunners* custom_task_runners) {
if (custom_task_runners == nullptr) {
return nullptr;
}
// The IO threads are always created by the engine and the embedder
// has no opportunity to specify task runners for the same.
//
// If/when more task runners are exposed, this mask will need to be updated.
uint64_t engine_thread_host_mask = ThreadHost::Type::IO;
auto platform_task_runner_pair =
CreateEmbedderTaskRunner(custom_task_runners->platform_task_runner);
auto render_task_runner_pair =
CreateEmbedderTaskRunner(custom_task_runners->render_task_runner);
auto ui_task_runner_pair =
CreateEmbedderTaskRunner(custom_task_runners->ui_task_runner);
if (!platform_task_runner_pair.first || !render_task_runner_pair.first ||
!ui_task_runner_pair.first) {
// User error while supplying a custom task runner. Return an invalid thread
// host. This will abort engine initialization. Don't fallback to defaults
// if the user wanted to specify a task runner but just messed up instead.
return nullptr;
}
// If the embedder has not supplied a GPU task runner, one needs to be
// created.
if (!render_task_runner_pair.second) {
engine_thread_host_mask |= ThreadHost::Type::GPU;
}
// If both the platform task runner and the GPU task runner are specified and
// have the same identifier, store only one.
if (platform_task_runner_pair.second && render_task_runner_pair.second) {
if (platform_task_runner_pair.second->GetEmbedderIdentifier() ==
render_task_runner_pair.second->GetEmbedderIdentifier()) {
render_task_runner_pair.second = platform_task_runner_pair.second;
}
}
if (platform_task_runner_pair.second && ui_task_runner_pair.second) {
if (platform_task_runner_pair.second->GetEmbedderIdentifier() ==
ui_task_runner_pair.second->GetEmbedderIdentifier()) {
ui_task_runner_pair.second = platform_task_runner_pair.second;
}
}
// Create a thread host with just the threads that need to be managed by the
// engine. The embedder has provided the rest.
ThreadHost thread_host(kUIWidgetsThreadName, engine_thread_host_mask);
// If the embedder has supplied a platform task runner, use that. If not, use
// the current thread task runner.
auto platform_task_runner =
platform_task_runner_pair.second
? static_cast<fml::RefPtr<fml::TaskRunner>>(
platform_task_runner_pair.second)
: GetCurrentThreadTaskRunner();
// If the embedder has supplied a GPU task runner, use that. If not, use the
// one from our thread host.
auto render_task_runner = render_task_runner_pair.second
? static_cast<fml::RefPtr<fml::TaskRunner>>(
render_task_runner_pair.second)
: thread_host.raster_thread->GetTaskRunner();
// If the embedder has supplied a ui task runner, use that. If not, use
// the current thread task runner.
auto ui_task_runner = ui_task_runner_pair.second
? static_cast<fml::RefPtr<fml::TaskRunner>>(
ui_task_runner_pair.second)
: GetCurrentThreadTaskRunner();
TaskRunners task_runners(
kUIWidgetsThreadName,
platform_task_runner, // platform
render_task_runner, // raster
ui_task_runner, // ui
thread_host.io_thread->GetTaskRunner() // io (always engine managed)
);
if (!task_runners.IsValid()) {
return nullptr;
}
std::set<fml::RefPtr<EmbedderTaskRunner>> embedder_task_runners;
if (platform_task_runner_pair.second) {
embedder_task_runners.insert(platform_task_runner_pair.second);
}
if (render_task_runner_pair.second) {
embedder_task_runners.insert(render_task_runner_pair.second);
}
if (ui_task_runner_pair.second) {
embedder_task_runners.insert(ui_task_runner_pair.second);
}
auto embedder_host = std::make_unique<EmbedderThreadHost>(
std::move(thread_host), task_runners, embedder_task_runners);
if (embedder_host->IsValid()) {
return embedder_host;
}
return nullptr;
}
EmbedderThreadHost::EmbedderThreadHost(
ThreadHost host, TaskRunners runners,
const std::set<fml::RefPtr<EmbedderTaskRunner>>& embedder_task_runners)
: host_(std::move(host)), runners_(runners) {
for (const auto& runner : embedder_task_runners) {
runners_map_[reinterpret_cast<int64_t>(runner.get())] = runner;
}
}
EmbedderThreadHost::~EmbedderThreadHost() = default;
bool EmbedderThreadHost::IsValid() const { return runners_.IsValid(); }
const TaskRunners& EmbedderThreadHost::GetTaskRunners() const {
return runners_;
}
bool EmbedderThreadHost::PostTask(int64_t runner, uint64_t task) const {
auto found = runners_map_.find(runner);
if (found == runners_map_.end()) {
return false;
}
return found->second->PostTask(task);
}
} // namespace uiwidgets

40
engine/src/shell/platform/embedder/embedder_thread_host.h


#pragma once
#include <map>
#include <memory>
#include <set>
#include "common/task_runners.h"
#include "embedder.h"
#include "embedder_task_runner.h"
#include "flutter/fml/macros.h"
#include "shell/common/thread_host.h"
namespace uiwidgets {
class EmbedderThreadHost {
public:
static std::unique_ptr<EmbedderThreadHost> CreateEmbedderManagedThreadHost(
const UIWidgetsCustomTaskRunners* custom_task_runners);
EmbedderThreadHost(
ThreadHost host, TaskRunners runners,
const std::set<fml::RefPtr<EmbedderTaskRunner>>& embedder_task_runners);
~EmbedderThreadHost();
bool IsValid() const;
const TaskRunners& GetTaskRunners() const;
bool PostTask(int64_t runner, uint64_t task) const;
private:
ThreadHost host_;
TaskRunners runners_;
std::map<int64_t, fml::RefPtr<EmbedderTaskRunner>> runners_map_;
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderThreadHost);
};
} // namespace uiwidgets

74
engine/src/shell/platform/embedder/platform_view_embedder.cc


#include "platform_view_embedder.h"
namespace uiwidgets {
PlatformViewEmbedder::PlatformViewEmbedder(
Delegate& delegate, TaskRunners task_runners,
EmbedderSurfaceGL::GLDispatchTable gl_dispatch_table,
bool fbo_reset_after_present, PlatformDispatchTable platform_dispatch_table,
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder)
: PlatformView(delegate, std::move(task_runners)),
embedder_surface_(std::make_unique<EmbedderSurfaceGL>(
gl_dispatch_table, fbo_reset_after_present,
std::move(external_view_embedder))),
platform_dispatch_table_(platform_dispatch_table) {}
PlatformViewEmbedder::PlatformViewEmbedder(
Delegate& delegate, TaskRunners task_runners,
EmbedderSurfaceSoftware::SoftwareDispatchTable software_dispatch_table,
PlatformDispatchTable platform_dispatch_table,
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder)
: PlatformView(delegate, std::move(task_runners)),
embedder_surface_(std::make_unique<EmbedderSurfaceSoftware>(
software_dispatch_table, std::move(external_view_embedder))),
platform_dispatch_table_(platform_dispatch_table) {}
PlatformViewEmbedder::~PlatformViewEmbedder() = default;
void PlatformViewEmbedder::HandlePlatformMessage(
fml::RefPtr<PlatformMessage> message) {
if (!message) {
return;
}
if (platform_dispatch_table_.platform_message_response_callback == nullptr) {
if (message->response()) {
message->response()->CompleteEmpty();
}
return;
}
platform_dispatch_table_.platform_message_response_callback(
std::move(message));
}
// |PlatformView|
std::unique_ptr<Surface> PlatformViewEmbedder::CreateRenderingSurface() {
if (embedder_surface_ == nullptr) {
FML_LOG(ERROR) << "Embedder surface was null.";
return nullptr;
}
return embedder_surface_->CreateGPUSurface();
}
// |PlatformView|
sk_sp<GrContext> PlatformViewEmbedder::CreateResourceContext() const {
if (embedder_surface_ == nullptr) {
FML_LOG(ERROR) << "Embedder surface was null.";
return nullptr;
}
return embedder_surface_->CreateResourceContext();
}
// |PlatformView|
std::unique_ptr<VsyncWaiter> PlatformViewEmbedder::CreateVSyncWaiter() {
if (!platform_dispatch_table_.vsync_callback) {
// Superclass implementation creates a timer based fallback.
return PlatformView::CreateVSyncWaiter();
}
return std::make_unique<VsyncWaiterEmbedder>(
platform_dispatch_table_.vsync_callback, task_runners_);
}
} // namespace uiwidgets

62
engine/src/shell/platform/embedder/platform_view_embedder.h


#pragma once
#include <functional>
#include "flutter/fml/macros.h"
#include "shell/common/platform_view.h"
#include "shell/platform/embedder/embedder.h"
#include "shell/platform/embedder/embedder_surface.h"
#include "shell/platform/embedder/embedder_surface_gl.h"
#include "shell/platform/embedder/embedder_surface_software.h"
#include "shell/platform/embedder/vsync_waiter_embedder.h"
namespace uiwidgets {
class PlatformViewEmbedder final : public PlatformView {
public:
using PlatformMessageResponseCallback =
std::function<void(fml::RefPtr<PlatformMessage>)>;
struct PlatformDispatchTable {
PlatformMessageResponseCallback
platform_message_response_callback; // optional
VsyncWaiterEmbedder::VsyncCallback vsync_callback; // optional
};
// Creates a platform view that sets up an OpenGL rasterizer.
PlatformViewEmbedder(
PlatformView::Delegate& delegate, TaskRunners task_runners,
EmbedderSurfaceGL::GLDispatchTable gl_dispatch_table,
bool fbo_reset_after_present,
PlatformDispatchTable platform_dispatch_table,
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder);
// Create a platform view that sets up a software rasterizer.
PlatformViewEmbedder(
PlatformView::Delegate& delegate, TaskRunners task_runners,
EmbedderSurfaceSoftware::SoftwareDispatchTable software_dispatch_table,
PlatformDispatchTable platform_dispatch_table,
std::unique_ptr<EmbedderExternalViewEmbedder> external_view_embedder);
~PlatformViewEmbedder() override;
// |PlatformView|
void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) override;
private:
std::unique_ptr<EmbedderSurface> embedder_surface_;
PlatformDispatchTable platform_dispatch_table_;
// |PlatformView|
std::unique_ptr<Surface> CreateRenderingSurface() override;
// |PlatformView|
sk_sp<GrContext> CreateResourceContext() const override;
// |PlatformView|
std::unique_ptr<VsyncWaiter> CreateVSyncWaiter() override;
FML_DISALLOW_COPY_AND_ASSIGN(PlatformViewEmbedder);
};
} // namespace uiwidgets

39
engine/src/shell/platform/embedder/vsync_waiter_embedder.cc


#include "vsync_waiter_embedder.h"
namespace uiwidgets {
VsyncWaiterEmbedder::VsyncWaiterEmbedder(const VsyncCallback& vsync_callback,
TaskRunners task_runners)
: VsyncWaiter(std::move(task_runners)), vsync_callback_(vsync_callback) {
FML_DCHECK(vsync_callback_);
}
VsyncWaiterEmbedder::~VsyncWaiterEmbedder() = default;
// |VsyncWaiter|
void VsyncWaiterEmbedder::AwaitVSync() {
auto* weak_waiter = new std::weak_ptr<VsyncWaiter>(shared_from_this());
vsync_callback_(reinterpret_cast<intptr_t>(weak_waiter));
}
// static
bool VsyncWaiterEmbedder::OnEmbedderVsync(intptr_t baton,
fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time) {
if (baton == 0) {
return false;
}
auto* weak_waiter = reinterpret_cast<std::weak_ptr<VsyncWaiter>*>(baton);
auto strong_waiter = weak_waiter->lock();
delete weak_waiter;
if (!strong_waiter) {
return false;
}
strong_waiter->FireCallback(frame_start_time, frame_target_time);
return true;
}
} // namespace uiwidgets

28
engine/src/shell/platform/embedder/vsync_waiter_embedder.h


#pragma once
#include "flutter/fml/macros.h"
#include "shell/common/vsync_waiter.h"
namespace uiwidgets {
class VsyncWaiterEmbedder final : public VsyncWaiter {
public:
using VsyncCallback = std::function<void(intptr_t)>;
VsyncWaiterEmbedder(const VsyncCallback& callback, TaskRunners task_runners);
~VsyncWaiterEmbedder() override;
static bool OnEmbedderVsync(intptr_t baton, fml::TimePoint frame_start_time,
fml::TimePoint frame_target_time);
private:
const VsyncCallback vsync_callback_;
// |VsyncWaiter|
void AwaitVSync() override;
FML_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterEmbedder);
};
} // namespace uiwidgets

43
engine/src/shell/platform/unity/gfx_worker_task_runner.cc


#include "gfx_worker_task_runner.h"
#include <flutter/fml/logging.h>
#include <flutter/fml/synchronization/waitable_event.h>
#include <flutter/fml/time/time_point.h>
#include <atomic>
#include <utility>
#include "uiwidgets_system.h"
namespace uiwidgets {
GfxWorkerTaskRunner::GfxWorkerTaskRunner(std::thread::id gfx_worker_thread_id,
TaskExpiredCallback on_task_expired)
: gfx_worker_thread_id_(gfx_worker_thread_id),
on_task_expired_(std::move(on_task_expired)),
weak_factory_(this) {}
GfxWorkerTaskRunner::~GfxWorkerTaskRunner() {
// drain pending tasks.
fml::AutoResetWaitableEvent latch;
UIWidgetsSystem::GetInstancePtr()->PostTaskToGfxWorker(
[&latch]() -> void { latch.Signal(); });
latch.Wait();
}
bool GfxWorkerTaskRunner::RunsTasksOnCurrentThread() const {
return std::this_thread::get_id() == gfx_worker_thread_id_;
}
void GfxWorkerTaskRunner::PostTask(UIWidgetsTask uiwidgets_task,
uint64_t uiwidgets_target_time_nanos) {
FML_DCHECK(uiwidgets_target_time_nanos <=
fml::TimePoint::Now().ToEpochDelta().ToNanoseconds());
UIWidgetsSystem::GetInstancePtr()->PostTaskToGfxWorker(
[&on_task_expired = on_task_expired_, uiwidgets_task]() -> void {
on_task_expired(&uiwidgets_task);
});
}
} // namespace uiwidgets

43
engine/src/shell/platform/unity/gfx_worker_task_runner.h


#pragma once
#include <windows.h>
#include <chrono>
#include <deque>
#include <functional>
#include <mutex>
#include <queue>
#include <thread>
#include <flutter/fml/memory/weak_ptr.h>
#include "flutter/fml/macros.h"
#include "shell/platform/embedder/embedder.h"
namespace uiwidgets {
class GfxWorkerTaskRunner {
public:
using TaskExpiredCallback = std::function<void(const UIWidgetsTask*)>;
GfxWorkerTaskRunner(std::thread::id gfx_worker_thread_id,
TaskExpiredCallback on_task_expired);
~GfxWorkerTaskRunner();
bool RunsTasksOnCurrentThread() const;
void PostTask(UIWidgetsTask uiwidgets_task,
uint64_t uiwidgets_target_time_nanos);
FML_DISALLOW_COPY_AND_ASSIGN(GfxWorkerTaskRunner);
private:
using TaskTimePoint = std::chrono::steady_clock::time_point;
std::thread::id gfx_worker_thread_id_;
TaskExpiredCallback on_task_expired_;
fml::WeakPtrFactory<GfxWorkerTaskRunner> weak_factory_;
};
} // namespace uiwidgets

281
engine/src/shell/platform/unity/uiwidgets_panel.cc


#include "uiwidgets_panel.h"
#include <Windows.h>
#include <flutter/fml/synchronization/waitable_event.h>
#include <iostream>
#include "lib/ui/window/viewport_metrics.h"
#include "runtime/mono_api.h"
#include "shell/platform/embedder/embedder_engine.h"
#include "uiwidgets_system.h"
namespace uiwidgets {
fml::RefPtr<UIWidgetsPanel> UIWidgetsPanel::Create(
Mono_Handle handle, EntrypointCallback entrypoint_callback) {
return fml::MakeRefCounted<UIWidgetsPanel>(handle, entrypoint_callback);
}
UIWidgetsPanel::UIWidgetsPanel(Mono_Handle handle,
EntrypointCallback entrypoint_callback)
: handle_(handle), entrypoint_callback_(entrypoint_callback) {}
UIWidgetsPanel::~UIWidgetsPanel() = default;
void UIWidgetsPanel::OnEnable(void* native_texture_ptr, size_t width,
size_t height, float device_pixel_ratio) {
surface_manager_ = std::make_unique<UnitySurfaceManager>(
UIWidgetsSystem::GetInstancePtr()->GetUnityInterfaces());
FML_DCHECK(fbo_ == 0);
surface_manager_->MakeCurrent(EGL_NO_DISPLAY);
fbo_ = surface_manager_->CreateRenderSurface(native_texture_ptr);
surface_manager_->ClearCurrent();
fml::AutoResetWaitableEvent latch;
std::thread::id gfx_worker_thread_id;
UIWidgetsSystem::GetInstancePtr()->PostTaskToGfxWorker(
[&latch, &gfx_worker_thread_id]() -> void {
gfx_worker_thread_id = std::this_thread::get_id();
latch.Signal();
});
latch.Wait();
gfx_worker_task_runner_ = std::make_unique<GfxWorkerTaskRunner>(
gfx_worker_thread_id, [this](const auto* task) {
if (UIWidgetsEngineRunTask(engine_, task) != kSuccess) {
std::cerr << "Could not post an gfx worker task." << std::endl;
}
});
UIWidgetsTaskRunnerDescription render_task_runner = {};
render_task_runner.struct_size = sizeof(UIWidgetsTaskRunnerDescription);
render_task_runner.identifier = 1;
render_task_runner.user_data = gfx_worker_task_runner_.get();
render_task_runner.runs_task_on_current_thread_callback =
[](void* user_data) -> bool {
return static_cast<GfxWorkerTaskRunner*>(user_data)
->RunsTasksOnCurrentThread();
};
render_task_runner.post_task_callback = [](UIWidgetsTask task,
uint64_t target_time_nanos,
void* user_data) -> void {
static_cast<GfxWorkerTaskRunner*>(user_data)->PostTask(task,
target_time_nanos);
};
UIWidgetsRendererConfig config = {};
config.type = kOpenGL;
config.open_gl.struct_size = sizeof(config.open_gl);
config.open_gl.clear_current = [](void* user_data) -> bool {
auto* panel = static_cast<UIWidgetsPanel*>(user_data);
return panel->surface_manager_->ClearCurrent();
};
config.open_gl.make_current = [](void* user_data) -> bool {
auto* panel = static_cast<UIWidgetsPanel*>(user_data);
return panel->surface_manager_->MakeCurrent(EGL_NO_DISPLAY);
};
config.open_gl.make_resource_current = [](void* user_data) -> bool {
auto* panel = static_cast<UIWidgetsPanel*>(user_data);
return panel->surface_manager_->MakeResourceCurrent();
};
config.open_gl.fbo_callback = [](void* user_data) -> uint32_t {
auto* panel = static_cast<UIWidgetsPanel*>(user_data);
return panel->fbo_;
};
config.open_gl.present = [](void* user_data) -> bool { return true; };
config.open_gl.gl_proc_resolver = [](void* user_data,
const char* what) -> void* {
return reinterpret_cast<void*>(eglGetProcAddress(what));
};
config.open_gl.fbo_reset_after_present = true;
task_runner_ = std::make_unique<Win32TaskRunner>(
GetCurrentThreadId(), [this](const auto* task) {
if (UIWidgetsEngineRunTask(engine_, task) != kSuccess) {
std::cerr << "Could not post an engine task." << std::endl;
}
});
UIWidgetsTaskRunnerDescription ui_task_runner = {};
ui_task_runner.struct_size = sizeof(UIWidgetsTaskRunnerDescription);
ui_task_runner.identifier = 2;
ui_task_runner.user_data = task_runner_.get();
ui_task_runner.runs_task_on_current_thread_callback =
[](void* user_data) -> bool {
return static_cast<Win32TaskRunner*>(user_data)->RunsTasksOnCurrentThread();
};
ui_task_runner.post_task_callback = [](UIWidgetsTask task,
uint64_t target_time_nanos,
void* user_data) -> void {
static_cast<Win32TaskRunner*>(user_data)->PostTask(task, target_time_nanos);
};
UIWidgetsCustomTaskRunners custom_task_runners = {};
custom_task_runners.struct_size = sizeof(UIWidgetsCustomTaskRunners);
custom_task_runners.platform_task_runner = &ui_task_runner;
custom_task_runners.ui_task_runner = &ui_task_runner;
custom_task_runners.render_task_runner = &render_task_runner;
UIWidgetsProjectArgs args = {};
args.struct_size = sizeof(UIWidgetsProjectArgs);
args.assets_path = "";
args.icu_data_path = "";
args.command_line_argc = 0;
args.command_line_argv = nullptr;
args.platform_message_callback =
[](const UIWidgetsPlatformMessage* engine_message,
void* user_data) -> void {};
args.custom_task_runners = &custom_task_runners;
args.task_observer_add = [](intptr_t key, void* callback,
void* user_data) -> void {
auto* panel = static_cast<UIWidgetsPanel*>(user_data);
panel->task_runner_->AddTaskObserver(key,
*static_cast<fml::closure*>(callback));
};
args.task_observer_remove = [](intptr_t key, void* user_data) -> void {
auto* panel = static_cast<UIWidgetsPanel*>(user_data);
panel->task_runner_->RemoveTaskObserver(key);
};
args.custom_mono_entrypoint = [](void* user_data) -> void {
auto* panel = static_cast<UIWidgetsPanel*>(user_data);
panel->MonoEntrypoint();
};
args.vsync_callback = [](void* user_data, intptr_t baton) -> void {
auto* panel = static_cast<UIWidgetsPanel*>(user_data);
panel->VSyncCallback(baton);
};
args.initial_window_metrics.width = width;
args.initial_window_metrics.height = height;
args.initial_window_metrics.pixel_ratio = device_pixel_ratio;
UIWidgetsEngine engine = nullptr;
auto result = UIWidgetsEngineInitialize(&config, &args, this, &engine);
if (result != kSuccess || engine == nullptr) {
std::cerr << "Failed to start UIWidgets engine: error " << result
<< std::endl;
return;
}
engine_ = engine;
UIWidgetsEngineRunInitialized(engine);
UIWidgetsSystem::GetInstancePtr()->RegisterPanel(this);
}
void UIWidgetsPanel::MonoEntrypoint() { entrypoint_callback_(handle_); }
void UIWidgetsPanel::OnDisable() {
// drain pending messages
ProcessMessages();
// drain pending vsync batons
ProcessVSync();
UIWidgetsSystem::GetInstancePtr()->UnregisterPanel(this);
if (engine_) {
UIWidgetsEngineShutdown(engine_);
engine_ = nullptr;
}
gfx_worker_task_runner_ = nullptr;
task_runner_ = nullptr;
if (fbo_) {
surface_manager_->MakeCurrent(EGL_NO_DISPLAY);
surface_manager_->DestroyRenderSurface();
fbo_ = 0;
surface_manager_->ClearCurrent();
}
surface_manager_ = nullptr;
}
void UIWidgetsPanel::OnRenderTexture(void* native_texture_ptr, size_t width,
size_t height, float device_pixel_ratio) {
reinterpret_cast<EmbedderEngine*>(engine_)->PostRenderThreadTask(
[this, native_texture_ptr]() -> void {
surface_manager_->MakeCurrent(EGL_NO_DISPLAY);
if (fbo_) {
surface_manager_->DestroyRenderSurface();
fbo_ = 0;
}
fbo_ = surface_manager_->CreateRenderSurface(native_texture_ptr);
surface_manager_->ClearCurrent();
});
ViewportMetrics metrics;
metrics.physical_width = width;
metrics.physical_height = height;
metrics.device_pixel_ratio = device_pixel_ratio;
reinterpret_cast<EmbedderEngine*>(engine_)->SetViewportMetrics(metrics);
}
std::chrono::nanoseconds UIWidgetsPanel::ProcessMessages() {
return std::chrono::nanoseconds(task_runner_->ProcessTasks().count());
}
void UIWidgetsPanel::ProcessVSync() {
std::vector<intptr_t> batons;
vsync_batons_.swap(batons);
for (intptr_t baton : batons) {
reinterpret_cast<EmbedderEngine*>(engine_)->OnVsyncEvent(
baton, fml::TimePoint::Now(),
fml::TimePoint::Now() +
fml::TimeDelta::FromNanoseconds(1000000000 / 60));
}
}
void UIWidgetsPanel::VSyncCallback(intptr_t baton) {
vsync_batons_.push_back(baton);
}
using TimePoint = std::chrono::steady_clock::time_point;
TimePoint next_flutter_event_time = TimePoint::clock::now();
UIWIDGETS_API(UIWidgetsPanel*)
UIWidgetsPanel_constructor(
Mono_Handle handle,
UIWidgetsPanel::EntrypointCallback entrypoint_callback) {
const auto panel = UIWidgetsPanel::Create(handle, entrypoint_callback);
panel->AddRef();
return panel.get();
}
UIWIDGETS_API(void) UIWidgetsPanel_dispose(UIWidgetsPanel* panel) {
panel->Release();
}
UIWIDGETS_API(void)
UIWidgetsPanel_onEnable(UIWidgetsPanel* panel, void* native_texture_ptr,
size_t width, size_t height, float device_pixel_ratio) {
panel->OnEnable(native_texture_ptr, width, height, device_pixel_ratio);
}
UIWIDGETS_API(void) UIWidgetsPanel_onDisable(UIWidgetsPanel* panel) {
panel->OnDisable();
}
UIWIDGETS_API(void)
UIWidgetsPanel_onRenderTexture(UIWidgetsPanel* panel, void* native_texture_ptr,
int width, int height, float dpi) {
panel->OnRenderTexture(native_texture_ptr, width, height, dpi);
}
} // namespace uiwidgets

55
engine/src/shell/platform/unity/uiwidgets_panel.h


#pragma once
#include <flutter/fml/memory/ref_counted.h>
#include "gfx_worker_task_runner.h"
#include "runtime/mono_api.h"
#include "unity_surface_manager.h"
#include "win32_task_runner.h"
namespace uiwidgets {
class UIWidgetsPanel : public fml::RefCountedThreadSafe<UIWidgetsPanel> {
FML_FRIEND_MAKE_REF_COUNTED(UIWidgetsPanel);
public:
typedef void (*EntrypointCallback)(Mono_Handle handle);
static fml::RefPtr<UIWidgetsPanel> Create(
Mono_Handle handle, EntrypointCallback entrypoint_callback);
~UIWidgetsPanel();
void OnEnable(void* native_texture_ptr, size_t width, size_t height,
float device_pixel_ratio);
void MonoEntrypoint();
void OnDisable();
void OnRenderTexture(void* native_texture_ptr, size_t width, size_t height,
float dpi);
std::chrono::nanoseconds ProcessMessages();
void ProcessVSync();
void VSyncCallback(intptr_t baton);
private:
UIWidgetsPanel(Mono_Handle handle, EntrypointCallback entrypoint_callback);
Mono_Handle handle_;
EntrypointCallback entrypoint_callback_;
std::unique_ptr<UnitySurfaceManager> surface_manager_;
GLuint fbo_ = 0;
std::unique_ptr<GfxWorkerTaskRunner> gfx_worker_task_runner_;
std::unique_ptr<Win32TaskRunner> task_runner_;
UIWidgetsEngine engine_ = nullptr;
std::vector<intptr_t> vsync_batons_;
};
} // namespace uiwidgets

95
engine/src/shell/platform/unity/uiwidgets_system.cc


#include "uiwidgets_system.h"
#include <algorithm>
#include <chrono>
#include "uiwidgets_panel.h"
namespace uiwidgets {
UIWidgetsSystem g_uiwidgets_system;
UIWidgetsSystem::UIWidgetsSystem() = default;
UIWidgetsSystem::~UIWidgetsSystem() = default;
void UIWidgetsSystem::RegisterPanel(UIWidgetsPanel* panel) {
uiwidgets_panels_.insert(panel);
}
void UIWidgetsSystem::UnregisterPanel(UIWidgetsPanel* panel) {
uiwidgets_panels_.erase(panel);
}
void UIWidgetsSystem::Wait(std::chrono::nanoseconds max_duration) {
std::chrono::nanoseconds wait_duration =
std::max(std::chrono::nanoseconds(0),
next_uiwidgets_event_time_ - TimePoint::clock::now());
wait_duration = std::min(max_duration, wait_duration);
::MsgWaitForMultipleObjects(0, nullptr, FALSE,
static_cast<DWORD>(wait_duration.count() / 1000),
QS_ALLINPUT);
}
void UIWidgetsSystem::Update() {
TimePoint next_event_time = TimePoint::max();
for (auto* uiwidgets_panel : uiwidgets_panels_) {
std::chrono::nanoseconds wait_duration = uiwidgets_panel->ProcessMessages();
if (wait_duration != std::chrono::nanoseconds::max()) {
next_event_time =
std::min(next_event_time, TimePoint::clock::now() + wait_duration);
}
}
next_uiwidgets_event_time_ = next_event_time;
}
void UIWidgetsSystem::VSync() {
for (auto* uiwidgets_panel : uiwidgets_panels_) {
uiwidgets_panel->ProcessVSync();
}
Update();
}
void UIWidgetsSystem::WakeUp() {}
void UIWidgetsSystem::GfxWorkerCallback(int eventId, void* data) {
const fml::closure task(std::move(gfx_worker_tasks_[eventId]));
gfx_worker_tasks_.erase(eventId);
task();
}
void UIWidgetsSystem::PostTaskToGfxWorker(const fml::closure& task) {
last_task_id_++;
gfx_worker_tasks_[last_task_id_] = task;
unity_uiwidgets_->IssuePluginEventAndData(&_GfxWorkerCallback, last_task_id_,
nullptr);
}
void UIWidgetsSystem::BindUnityInterfaces(IUnityInterfaces* unity_interfaces) {
unity_interfaces_ = unity_interfaces;
unity_uiwidgets_ = unity_interfaces_->Get<UnityUIWidgets::IUnityUIWidgets>();
unity_uiwidgets_->SetUpdateCallback(_Update);
unity_uiwidgets_->SetVSyncCallback(_VSync);
unity_uiwidgets_->SetWaitCallback(_Wait);
unity_uiwidgets_->SetWakeUpCallback(_WakeUp);
}
void UIWidgetsSystem::UnBindUnityInterfaces() {
unity_uiwidgets_->SetUpdateCallback(nullptr);
unity_uiwidgets_->SetVSyncCallback(nullptr);
unity_uiwidgets_->SetWaitCallback(nullptr);
unity_uiwidgets_->SetWakeUpCallback(nullptr);
unity_uiwidgets_ = nullptr;
unity_interfaces_ = nullptr;
}
UIWidgetsSystem* UIWidgetsSystem::GetInstancePtr() {
return &g_uiwidgets_system;
}
} // namespace uiwidgets

69
engine/src/shell/platform/unity/uiwidgets_system.h


#pragma once
#include <flutter/fml/closure.h>
#include <chrono>
#include <set>
#include <unordered_map>
#include "Unity/IUnityInterface.h"
#include "Unity/IUnityUIWidgets.h"
#include "flutter/fml/macros.h"
#include "runtime/mono_api.h"
namespace uiwidgets {
using TimePoint = std::chrono::steady_clock::time_point;
class UIWidgetsPanel;
class UIWidgetsSystem {
public:
UIWidgetsSystem();
~UIWidgetsSystem();
void RegisterPanel(UIWidgetsPanel* panel);
void UnregisterPanel(UIWidgetsPanel* panel);
void PostTaskToGfxWorker(const fml::closure& task);
void BindUnityInterfaces(IUnityInterfaces* unity_interfaces);
void UnBindUnityInterfaces();
IUnityInterfaces* GetUnityInterfaces() { return unity_interfaces_; }
static UIWidgetsSystem* GetInstancePtr();
FML_DISALLOW_COPY_AND_ASSIGN(UIWidgetsSystem);
private:
UIWIDGETS_CALLBACK(void) _Update() { GetInstancePtr()->Update(); }
UIWIDGETS_CALLBACK(void) _Wait(long max_duration) {
GetInstancePtr()->Wait(std::chrono::nanoseconds(max_duration));
}
UIWIDGETS_CALLBACK(void) _VSync() { GetInstancePtr()->VSync(); }
UIWIDGETS_CALLBACK(void) _WakeUp() { GetInstancePtr()->WakeUp(); }
UIWIDGETS_CALLBACK(void) _GfxWorkerCallback(int eventId, void* data) {
GetInstancePtr()->GfxWorkerCallback(eventId, data);
}
void Update();
void Wait(std::chrono::nanoseconds max_duration);
void VSync();
void WakeUp();
void GfxWorkerCallback(int eventId, void* data);
IUnityInterfaces* unity_interfaces_ = nullptr;
UnityUIWidgets::IUnityUIWidgets* unity_uiwidgets_ = nullptr;
std::unordered_map<int, fml::closure> gfx_worker_tasks_;
int last_task_id_ = 0;
TimePoint next_uiwidgets_event_time_ = TimePoint::clock::now();
std::set<UIWidgetsPanel*> uiwidgets_panels_;
};
} // namespace uiwidgets

231
engine/src/shell/platform/unity/unity_surface_manager.cc


#include "unity_surface_manager.h"
#include <d3d11.h>
#include <dxgi.h>
#include <flutter/fml/logging.h>
#include "Unity/IUnityGraphics.h"
#include "Unity/IUnityGraphicsD3D11.h"
namespace uiwidgets {
UnitySurfaceManager::UnitySurfaceManager(IUnityInterfaces* unity_interfaces)
: egl_display_(EGL_NO_DISPLAY),
egl_context_(EGL_NO_CONTEXT),
egl_resource_context_(EGL_NO_CONTEXT),
egl_config_(nullptr) {
initialize_succeeded_ = Initialize(unity_interfaces);
}
UnitySurfaceManager::~UnitySurfaceManager() { CleanUp(); }
GLuint UnitySurfaceManager::CreateRenderSurface(void* native_texture_ptr) {
ID3D11Texture2D* d3d11_texture =
static_cast<ID3D11Texture2D*>(native_texture_ptr);
IDXGIResource* image_resource;
HRESULT hr = d3d11_texture->QueryInterface(
__uuidof(IDXGIResource), reinterpret_cast<void**>(&image_resource));
FML_CHECK(SUCCEEDED(hr)) << "UnitySurfaceManager: QueryInterface() failed";
HANDLE shared_image_handle;
hr = image_resource->GetSharedHandle(&shared_image_handle);
FML_CHECK(SUCCEEDED(hr)) << "UnitySurfaceManager: GetSharedHandle() failed";
image_resource->Release();
FML_CHECK(shared_image_handle != nullptr)
<< "UnitySurfaceManager: shared_image_handle is nullptr, miscFlags "
"D3D11_RESOURCE_MISC_SHARED is needed";
IDXGIResource* dxgi_resource;
hr = d3d11_device_->OpenSharedResource(
shared_image_handle, __uuidof(ID3D11Resource),
reinterpret_cast<void**>(&dxgi_resource));
FML_CHECK(SUCCEEDED(hr))
<< "UnitySurfaceManager: failed to open shared resource";
ID3D11Texture2D* image_texture;
hr = dxgi_resource->QueryInterface(__uuidof(ID3D11Texture2D),
reinterpret_cast<void**>(&image_texture));
FML_CHECK(SUCCEEDED(hr))
<< "UnitySurfaceManager: failed to query interface ID3D11Texture2D";
dxgi_resource->Release();
const EGLint attribs[] = {EGL_NONE};
FML_DCHECK(fbo_egl_image_ == nullptr);
fbo_egl_image_ =
eglCreateImageKHR(egl_display_, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE,
static_cast<EGLClientBuffer>(image_texture), attribs);
FML_CHECK(fbo_egl_image_ != EGL_NO_IMAGE_KHR);
image_texture->Release();
FML_DCHECK(fbo_texture_ == 0);
glGenTextures(1, &fbo_texture_);
glBindTexture(GL_TEXTURE_2D, fbo_texture_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, fbo_egl_image_);
FML_DCHECK(fbo_ == 0);
glGenFramebuffers(1, &fbo_);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
fbo_texture_, 0);
FML_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) ==
GL_FRAMEBUFFER_COMPLETE);
return fbo_;
}
void UnitySurfaceManager::DestroyRenderSurface() {
FML_DCHECK(fbo_ != 0);
glDeleteFramebuffers(1, &fbo_);
fbo_ = 0;
FML_DCHECK(fbo_texture_ != 0);
glDeleteTextures(1, &fbo_texture_);
fbo_texture_ = 0;
FML_DCHECK(fbo_egl_image_ != nullptr);
eglDestroyImageKHR(egl_display_, fbo_egl_image_);
fbo_egl_image_ = nullptr;
}
bool UnitySurfaceManager::ClearCurrent() {
return eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT) == EGL_TRUE;
}
bool UnitySurfaceManager::MakeCurrent(const EGLSurface surface) {
return eglMakeCurrent(egl_display_, surface, surface, egl_context_) ==
EGL_TRUE;
}
bool UnitySurfaceManager::MakeResourceCurrent() {
return eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
egl_resource_context_) == EGL_TRUE;
}
bool UnitySurfaceManager::Initialize(IUnityInterfaces* unity_interfaces) {
IUnityGraphics* graphics = unity_interfaces->Get<IUnityGraphics>();
FML_CHECK(graphics->GetRenderer() == kUnityGfxRendererD3D11)
<< "Renderer type is invalid";
IUnityGraphicsD3D11* d3d11 = unity_interfaces->Get<IUnityGraphicsD3D11>();
ID3D11Device* d3d11_device = d3d11->GetDevice();
IDXGIDevice* dxgi_device;
HRESULT hr = d3d11_device->QueryInterface(
__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgi_device));
FML_CHECK(SUCCEEDED(hr)) << "d3d11_device->QueryInterface(...) failed";
IDXGIAdapter* dxgi_adapter;
hr = dxgi_device->GetAdapter(&dxgi_adapter);
FML_CHECK(SUCCEEDED(hr)) << "dxgi_adapter->GetAdapter(...) failed";
dxgi_device->Release();
DXGI_ADAPTER_DESC adapter_desc;
hr = dxgi_adapter->GetDesc(&adapter_desc);
FML_CHECK(SUCCEEDED(hr)) << "dxgi_adapter->GetDesc(...) failed";
dxgi_adapter->Release();
EGLint displayAttribs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE,
adapter_desc.AdapterLuid.HighPart,
EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE,
adapter_desc.AdapterLuid.LowPart,
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
EGL_TRUE,
EGL_NONE};
egl_display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
EGL_DEFAULT_DISPLAY, displayAttribs);
FML_CHECK(egl_display_ != EGL_NO_DISPLAY)
<< "EGL: Failed to get a compatible EGLdisplay";
if (eglInitialize(egl_display_, nullptr, nullptr) == EGL_FALSE) {
FML_CHECK(false) << "EGL: Failed to initialize EGL";
}
EGLAttrib egl_device = 0;
eglQueryDisplayAttribEXT(egl_display_, EGL_DEVICE_EXT, &egl_device);
EGLAttrib angle_device = 0;
eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(egl_device),
EGL_D3D11_DEVICE_ANGLE, &angle_device);
d3d11_device_ = reinterpret_cast<ID3D11Device*>(angle_device);
const EGLint configAttributes[] = {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8,
EGL_NONE};
EGLint numConfigs = 0;
if (eglChooseConfig(egl_display_, configAttributes, &egl_config_, 1,
&numConfigs) == EGL_FALSE ||
numConfigs == 0) {
FML_CHECK(false) << "EGL: Failed to choose first context";
}
const EGLint display_context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE};
egl_context_ = eglCreateContext(egl_display_, egl_config_, EGL_NO_CONTEXT,
display_context_attributes);
if (egl_context_ == EGL_NO_CONTEXT) {
FML_CHECK(false) << "EGL: Failed to create EGL context";
}
egl_resource_context_ = eglCreateContext(
egl_display_, egl_config_, egl_context_, display_context_attributes);
if (egl_resource_context_ == EGL_NO_CONTEXT) {
FML_CHECK(false) << "EGL: Failed to create EGL resource context";
}
return true;
}
void UnitySurfaceManager::CleanUp() {
EGLBoolean result = EGL_FALSE;
if (egl_display_ != EGL_NO_DISPLAY && egl_context_ != EGL_NO_CONTEXT) {
result = eglDestroyContext(egl_display_, egl_context_);
egl_context_ = EGL_NO_CONTEXT;
if (result == EGL_FALSE) {
FML_LOG(ERROR) << "EGL: Failed to destroy context";
}
}
d3d11_device_ = nullptr;
if (egl_display_ != EGL_NO_DISPLAY &&
egl_resource_context_ != EGL_NO_CONTEXT) {
result = eglDestroyContext(egl_display_, egl_resource_context_);
egl_resource_context_ = EGL_NO_CONTEXT;
if (result == EGL_FALSE) {
FML_LOG(ERROR) << "EGL : Failed to destroy resource context";
}
}
if (egl_display_ != EGL_NO_DISPLAY) {
result = eglTerminate(egl_display_);
egl_display_ = EGL_NO_DISPLAY;
if (result == EGL_FALSE) {
FML_LOG(ERROR) << "EGL : Failed to terminate EGL";
}
}
}
} // namespace uiwidgets

51
engine/src/shell/platform/unity/unity_surface_manager.h


#pragma once
// OpenGL ES and EGL includes
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <d3d11.h>
#include <windows.h>
#include <cstdint>
#include "Unity/IUnityInterface.h"
#include "flutter/fml/macros.h"
namespace uiwidgets {
class UnitySurfaceManager {
public:
UnitySurfaceManager(IUnityInterfaces* unity_interfaces);
~UnitySurfaceManager();
GLuint CreateRenderSurface(void* native_texture_ptr);
void DestroyRenderSurface();
bool ClearCurrent();
bool MakeCurrent(const EGLSurface surface);
bool MakeResourceCurrent();
FML_DISALLOW_COPY_AND_ASSIGN(UnitySurfaceManager);
private:
bool Initialize(IUnityInterfaces* unity_interfaces);
void CleanUp();
EGLDisplay egl_display_;
EGLContext egl_context_;
EGLContext egl_resource_context_;
EGLConfig egl_config_;
bool initialize_succeeded_;
ID3D11Device* d3d11_device_;
EGLImage fbo_egl_image_ = nullptr;
GLuint fbo_texture_ = 0;
GLuint fbo_ = 0;
};
} // namespace uiwidgets

116
engine/src/shell/platform/unity/win32_task_runner.cc


#include "win32_task_runner.h"
#include <flutter/fml/time/time_point.h>
#include <atomic>
#include <utility>
namespace uiwidgets {
Win32TaskRunner::Win32TaskRunner(DWORD main_thread_id,
const TaskExpiredCallback& on_task_expired)
: main_thread_id_(main_thread_id),
on_task_expired_(std::move(on_task_expired)) {}
Win32TaskRunner::~Win32TaskRunner() = default;
bool Win32TaskRunner::RunsTasksOnCurrentThread() const {
return GetCurrentThreadId() == main_thread_id_;
}
std::chrono::nanoseconds Win32TaskRunner::ProcessTasks() {
const TaskTimePoint now = TaskTimePoint::clock::now();
std::vector<UIWidgetsTask> expired_tasks;
// Process expired tasks.
{
std::lock_guard<std::mutex> lock(task_queue_mutex_);
while (!task_queue_.empty()) {
const auto& top = task_queue_.top();
// If this task (and all tasks after this) has not yet expired, there is
// nothing more to do. Quit iterating.
if (top.fire_time > now) {
break;
}
// Make a record of the expired task. Do NOT service the task here
// because we are still holding onto the task queue mutex. We don't want
// other threads to block on posting tasks onto this thread till we are
// done processing expired tasks.
expired_tasks.push_back(task_queue_.top().task);
// Remove the tasks from the delayed tasks queue.
task_queue_.pop();
}
}
// Fire expired tasks.
{
// Flushing tasks here without holing onto the task queue mutex.
for (const auto& task : expired_tasks) {
on_task_expired_(&task);
for (const auto& observer : task_observers_) {
observer.second();
}
}
}
if (!expired_tasks.empty())
{
return ProcessTasks();
}
// Calculate duration to sleep for on next iteration.
{
std::lock_guard<std::mutex> lock(task_queue_mutex_);
const auto next_wake = task_queue_.empty() ? TaskTimePoint::max()
: task_queue_.top().fire_time;
return std::min(next_wake - now, std::chrono::nanoseconds::max());
}
}
Win32TaskRunner::TaskTimePoint Win32TaskRunner::TimePointFromUIWidgetsTime(
uint64_t uiwidgets_target_time_nanos) {
const auto now = TaskTimePoint::clock::now();
const auto uiwidgets_duration =
uiwidgets_target_time_nanos -
fml::TimePoint::Now().ToEpochDelta().ToNanoseconds();
return now + std::chrono::nanoseconds(uiwidgets_duration);
}
void Win32TaskRunner::PostTask(UIWidgetsTask uiwidgets_task,
uint64_t uiwidgets_target_time_nanos) {
static std::atomic_uint64_t sGlobalTaskOrder(0);
Task task;
task.order = ++sGlobalTaskOrder;
task.fire_time = TimePointFromUIWidgetsTime(uiwidgets_target_time_nanos);
task.task = uiwidgets_task;
{
std::lock_guard<std::mutex> lock(task_queue_mutex_);
task_queue_.push(task);
// Make sure the queue mutex is unlocked before waking up the loop. In case
// the wake causes this thread to be descheduled for the primary thread to
// process tasks, the acquisition of the lock on that thread while holding
// the lock here momentarily till the end of the scope is a pessimization.
}
if (!PostThreadMessage(main_thread_id_, WM_NULL, 0, 0)) {
OutputDebugString(L"Failed to post message to main thread.");
}
}
void Win32TaskRunner::AddTaskObserver(intptr_t key,
const fml::closure& callback) {
task_observers_[key] = callback;
}
void Win32TaskRunner::RemoveTaskObserver(intptr_t key) {
task_observers_.erase(key);
}
} // namespace uiwidgets

73
engine/src/shell/platform/unity/win32_task_runner.h


#pragma once
#include <flutter/fml/closure.h>
#include <windows.h>
#include <chrono>
#include <deque>
#include <functional>
#include <map>
#include <mutex>
#include <queue>
#include <thread>
#include "shell/platform/embedder/embedder.h"
namespace uiwidgets {
class Win32TaskRunner {
public:
using TaskExpiredCallback = std::function<void(const UIWidgetsTask*)>;
Win32TaskRunner(DWORD main_thread_id,
const TaskExpiredCallback& on_task_expired);
~Win32TaskRunner();
// Returns if the current thread is the thread used by the win32 event loop.
bool RunsTasksOnCurrentThread() const;
std::chrono::nanoseconds ProcessTasks();
// Post a Flutter engine tasks to the event loop for delayed execution.
void PostTask(UIWidgetsTask uiwidgets_task,
uint64_t uiwidgets_target_time_nanos);
void AddTaskObserver(intptr_t key, const fml::closure& callback);
void RemoveTaskObserver(intptr_t key);
FML_DISALLOW_COPY_AND_ASSIGN(Win32TaskRunner);
private:
using TaskTimePoint = std::chrono::steady_clock::time_point;
struct Task {
uint64_t order;
TaskTimePoint fire_time;
UIWidgetsTask task;
struct Comparer {
bool operator()(const Task& a, const Task& b) {
if (a.fire_time == b.fire_time) {
return a.order > b.order;
}
return a.fire_time > b.fire_time;
}
};
};
DWORD main_thread_id_;
TaskExpiredCallback on_task_expired_;
std::mutex task_queue_mutex_;
std::priority_queue<Task, std::deque<Task>, Task::Comparer> task_queue_;
std::condition_variable task_queue_cv_;
using TaskObservers = std::map<intptr_t, fml::closure>;
TaskObservers task_observers_;
static TaskTimePoint TimePointFromUIWidgetsTime(
uint64_t flutter_target_time_nanos);
};
} // namespace uiwidgets
正在加载...
取消
保存