浏览代码

Merge branch 'zxw/skia_mac_dev' of github.com:Unity-Technologies/com.unity.uiwidgets into dev_1.17.5

# Conflicts:
#	com.unity.uiwidgets/Runtime/cupertino.meta
#	com.unity.uiwidgets/Runtime/semantics.meta
/siyaoH-1.17-PlatformMessage
xingweizhu 4 年前
当前提交
e1cd46a6
共有 45 个文件被更改,包括 1770 次插入271 次删除
  1. 175
      com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs
  2. 253
      engine/Build.bee.cs
  3. 101
      engine/README.md
  4. 90
      engine/src/engine.cc
  5. 2
      engine/src/lib/ui/text/asset_manager_font_provider.cc
  6. 2
      engine/src/lib/ui/text/font_collection.cc
  7. 2
      engine/src/lib/ui/text/icu_util.cc
  8. 1
      engine/src/lib/ui/text/paragraph.cc
  9. 1
      engine/src/lib/ui/text/paragraph_builder.cc
  10. 4
      engine/src/lib/ui/window/pointer_data.h
  11. 10
      engine/src/runtime/mono_api.cc
  12. 2
      engine/src/shell/platform/unity/gfx_worker_task_runner.h
  13. 79
      engine/src/shell/platform/unity/uiwidgets_system.h
  14. 4
      engine/third_party/Unity/IUnityUIWidgets.h
  15. 2
      engine/src/shell/platform/unity/windows/uiwidgets_panel.h
  16. 106
      engine/src/shell/platform/unity/darwin/macos/cocoa_task_runner.cc
  17. 66
      engine/src/shell/platform/unity/darwin/macos/cocoa_task_runner.h
  18. 105
      engine/src/shell/platform/unity/darwin/macos/uiwidgets_panel.h
  19. 448
      engine/src/shell/platform/unity/darwin/macos/uiwidgets_panel.mm
  20. 76
      engine/src/shell/platform/unity/darwin/macos/uiwidgets_system.h
  21. 94
      engine/src/shell/platform/unity/darwin/macos/uiwidgets_system.mm
  22. 49
      engine/src/shell/platform/unity/darwin/macos/unity_surface_manager.h
  23. 192
      engine/src/shell/platform/unity/darwin/macos/unity_surface_manager.mm
  24. 76
      engine/src/shell/platform/unity/windows/uiwidgets_system.h
  25. 101
      engine/src/tests/render_engine.cc
  26. 0
      /engine/src/shell/platform/unity/windows/uiwidgets_panel.cc
  27. 0
      /engine/src/shell/platform/unity/windows/uiwidgets_panel.h
  28. 0
      /engine/src/shell/platform/unity/windows/unity_surface_manager.cc
  29. 0
      /engine/src/shell/platform/unity/windows/unity_surface_manager.h
  30. 0
      /engine/src/shell/platform/unity/windows/win32_task_runner.h
  31. 0
      /engine/src/shell/platform/unity/windows/unity_external_texture_gl.cc
  32. 0
      /engine/src/shell/platform/unity/windows/unity_external_texture_gl.h
  33. 0
      /engine/src/shell/platform/unity/windows/win32_task_runner.cc
  34. 0
      /engine/src/shell/platform/unity/windows/uiwidgets_system.cc
  35. 0
      /engine/src/tests/render_api.cc
  36. 0
      /engine/src/tests/render_api.h
  37. 0
      /engine/src/tests/render_api_d3d11.cc
  38. 0
      /engine/src/tests/render_api_opengles.cc
  39. 0
      /engine/src/tests/render_api_vulkan.cc
  40. 0
      /engine/src/tests/TestLoadICU.cpp
  41. 0
      /engine/src/tests/TestLoadICU.h

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


using NativeBindings = Unity.UIWidgets.ui.NativeBindings;
namespace Unity.UIWidgets.engine2 {
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
public partial class UIWidgetsPanel {
RenderTexture _renderTexture;
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;
}
void _enableUIWidgetsPanel(string font_settings)
{
UIWidgetsPanel_onEnable(_ptr, _renderTexture.GetNativeTexturePtr(),
_width, _height, _devicePixelRatio, Application.streamingAssetsPath, font_settings);
}
void _resizeUIWidgetsPanel()
{
UIWidgetsPanel_onRenderTexture(_ptr,
_renderTexture.GetNativeTexturePtr(),
_width, _height, _devicePixelRatio);
}
void _disableUIWidgetsPanel() {
_renderTexture = null;
texture = null;
}
[DllImport(NativeBindings.dllName)]
static extern void UIWidgetsPanel_onEnable(IntPtr ptr,
IntPtr nativeTexturePtr, int width, int height, float dpi, string streamingAssetsPath, string font_settings);
[DllImport(NativeBindings.dllName)]
static extern void UIWidgetsPanel_onRenderTexture(
IntPtr ptr, IntPtr nativeTexturePtr, int width, int height, float dpi);
}
#elif UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
public partial class UIWidgetsPanel {
Texture _renderTexture;
void _createRenderTexture(int width, int height, float devicePixelRatio) {
D.assert(_renderTexture == null);
_width = width;
_height = height;
_devicePixelRatio = devicePixelRatio;
}
void _destroyRenderTexture() {
D.assert(_renderTexture != null);
var releaseOK = UIWidgetsPanel_releaseNativeTexture(_ptr);
D.assert(releaseOK);
_renderTexture = null;
texture = null;
}
void _enableUIWidgetsPanel(string font_settings) {
D.assert(_renderTexture == null);
IntPtr native_tex_ptr = UIWidgetsPanel_onEnable(_ptr, _width, _height, _devicePixelRatio,
Application.streamingAssetsPath, font_settings);
D.assert(native_tex_ptr != IntPtr.Zero);
_renderTexture =
Texture2D.CreateExternalTexture(_width, _height, TextureFormat.BGRA32, false, true, native_tex_ptr);
texture = _renderTexture;
}
void _disableUIWidgetsPanel() {
_renderTexture = null;
texture = null;
}
void _resizeUIWidgetsPanel()
{
D.assert(_renderTexture == null);
IntPtr native_tex_ptr = UIWidgetsPanel_onRenderTexture(_ptr, _width, _height, _devicePixelRatio);
D.assert(native_tex_ptr != IntPtr.Zero);
_renderTexture =
Texture2D.CreateExternalTexture(_width, _height, TextureFormat.BGRA32, false, true, native_tex_ptr);
texture = _renderTexture;
}
[DllImport(NativeBindings.dllName)]
static extern IntPtr UIWidgetsPanel_onEnable(IntPtr ptr,
int width, int height, float dpi, string streamingAssetsPath, string font_settings);
[DllImport(NativeBindings.dllName)]
static extern bool UIWidgetsPanel_releaseNativeTexture(IntPtr ptr);
[DllImport(NativeBindings.dllName)]
static extern IntPtr UIWidgetsPanel_onRenderTexture(
IntPtr ptr, int width, int height, float dpi);
}
#endif
public partial class UIWidgetsPanel : RawImage {
[Serializable]
public struct Font {

IntPtr _ptr;
GCHandle _handle;
RenderTexture _renderTexture;
int _width;
int _height;
float _devicePixelRatio;

protected void OnEnable() {
base.OnEnable();
D.assert(_renderTexture == null);
UIWidgetsPanel_onEnable(_ptr, _renderTexture.GetNativeTexturePtr(),
_width, _height, _devicePixelRatio, Application.streamingAssetsPath,
JSONMessageCodec.instance.toJson(settings));
_enableUIWidgetsPanel(JSONMessageCodec.instance.toJson(settings));
Input_OnEnable();
NativeConsole.OnEnable();

protected override void OnRectTransformDimensionsChange() {
if (_ptr != IntPtr.Zero && _renderTexture) {
if (_recreateRenderTexture(_currentWidth, _currentHeight, _currentDevicePixelRatio)) {
UIWidgetsPanel_onRenderTexture(_ptr,
_renderTexture.GetNativeTexturePtr(),
_width, _height, _devicePixelRatio);
_resizeUIWidgetsPanel();
}
}
}

_handle.Free();
_handle = default;
// _destroyRenderTexture();
// Destroy(_rawImage);
_disableUIWidgetsPanel();
D.assert(!isolate.isValid);
base.OnDisable();
}

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;
}
protected virtual void Update() {
Input_Update();
}

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, string streamingAssetsPath, string settings);
[DllImport(NativeBindings.dllName)]
[DllImport(NativeBindings.dllName)]
static extern void UIWidgetsPanel_onRenderTexture(
IntPtr ptr, IntPtr nativeTexturePtr, int width, int height, float dpi);
[DllImport(NativeBindings.dllName)]
static extern int UIWidgetsPanel_registerTexture(IntPtr ptr, IntPtr nativeTexturePtr);

253
engine/Build.bee.cs


using Bee.Tools;
using NiceIO;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Bee.ProjectGeneration.XCode;
using Bee.Toolchain.Xcode;
class BuildUtils
{
public static bool IsHostWindows()
{
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
}
public static bool IsHostMac()
{
return RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
}
}
class Build
{

flutterRoot = Environment.GetEnvironmentVariable("USERPROFILE") + "/engine/src";
}
var builder = new VisualStudioNativeProjectFileBuilder(libUIWidgets);
builder = libUIWidgets.SetupConfigurations.Aggregate(
builder,
(current, c) => current.AddProjectConfiguration(c));
//create ide projects
if (BuildUtils.IsHostWindows())
{
//create vs project
var builder = new VisualStudioNativeProjectFileBuilder(libUIWidgets);
builder = libUIWidgets.SetupConfigurations.Aggregate(
builder,
(current, c) => current.AddProjectConfiguration(c));
var sln = new VisualStudioSolution();
sln.Path = "libUIWidgets.gen.sln";
sln.Projects.Add(builder.DeployTo("libUIWidgets.gen.vcxproj"));
Backend.Current.AddAliasDependency("ProjectFiles", sln.Setup());
var sln = new VisualStudioSolution();
sln.Path = "libUIWidgets.gen.sln";
sln.Projects.Add(builder.DeployTo("libUIWidgets.gen.vcxproj"));
Backend.Current.AddAliasDependency("ProjectFiles", sln.Setup());
}
else if (BuildUtils.IsHostMac())
{
//create xcode project
var nativePrograms = new List<NativeProgram>();
nativePrograms.Add(libUIWidgets);
var xcodeProject = new XCodeProjectFile(nativePrograms, new NPath("libUIWidgets.xcodeproj/project.pbxproj"));
}
}
private static string skiaRoot;

"src/shell/platform/unity/gfx_worker_task_runner.cc",
"src/shell/platform/unity/gfx_worker_task_runner.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/unity_external_texture_gl.cc",
"src/shell/platform/unity/unity_external_texture_gl.h",
"src/shell/platform/unity/unity_surface_manager.cc",
"src/shell/platform/unity/unity_surface_manager.h",
"src/shell/platform/unity/win32_task_runner.cc",
"src/shell/platform/unity/win32_task_runner.h",
"src/shell/platform/unity/unity_console.cc",
"src/shell/platform/unity/unity_console.h",

"src/engine.cc",
"src/platform_base.h",
"src/render_api.cc",
"src/render_api.h",
"src/render_api_d3d11.cc",
"src/TestLoadICU.cpp", // load icu temp solution
//"src/render_api_vulkan.cc",
//"src/render_api_opengles.cc",
np.Libraries.Add(new BagOfObjectFilesLibrary(
// include these files for test only
var testSources = new NPath[] {
"src/tests/render_engine.cc",
"src/tests/render_api.cc",
"src/tests/render_api.h",
"src/tests/render_api_d3d11.cc", // test d3d rendering
"src/tests/render_api_vulkan.cc", // test vulkan rendering
"src/tests/render_api_opengles.cc", // test opengles rendering
"src/tests/TestLoadICU.cpp", // test ICU
};
var winSources = new NPath[] {
"src/shell/platform/unity/windows/uiwidgets_panel.cc",
"src/shell/platform/unity/windows/uiwidgets_panel.h",
"src/shell/platform/unity/windows/uiwidgets_system.cc",
"src/shell/platform/unity/windows/uiwidgets_system.h",
"src/shell/platform/unity/windows/unity_external_texture_gl.cc",
"src/shell/platform/unity/windows/unity_external_texture_gl.h",
"src/shell/platform/unity/windows/unity_surface_manager.cc",
"src/shell/platform/unity/windows/unity_surface_manager.h",
"src/shell/platform/unity/windows/win32_task_runner.cc",
"src/shell/platform/unity/windows/win32_task_runner.h",
};
var macSources = new NPath[] {
"src/shell/platform/unity/darwin/macos/uiwidgets_panel.mm",
"src/shell/platform/unity/darwin/macos/uiwidgets_panel.h",
"src/shell/platform/unity/darwin/macos/uiwidgets_system.mm",
"src/shell/platform/unity/darwin/macos/uiwidgets_system.h",
"src/shell/platform/unity/darwin/macos/cocoa_task_runner.cc",
"src/shell/platform/unity/darwin/macos/cocoa_task_runner.h",
"src/shell/platform/unity/darwin/macos/unity_surface_manager.mm",
"src/shell/platform/unity/darwin/macos/unity_surface_manager.h",
};
np.Sources.Add(c => IsWindows(c), winSources);
np.Sources.Add(c => IsMac(c), macSources);
np.Libraries.Add(c => IsWindows(c), new BagOfObjectFilesLibrary(
np.CompilerSettings().Add(c => IsMac(c), c => c.WithCustomFlags(new []{"-Wno-c++11-narrowing"}));
np.Defines.Add(c => IsMac(c), "UIWIDGETS_FORCE_ALIGNAS_8=\\\"1\\\"");
np.Defines.Add(c => c.CodeGen == CodeGen.Debug,
new[] { "_ITERATOR_DEBUG_LEVEL=2", "_HAS_ITERATOR_DEBUGGING=1", "_SECURE_SCL=1" });

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

var toolchain = ToolChain.Store.Windows().VS2019().Sdk_17134().x64();
var codegens = new[] { CodeGen.Debug };
var codegens = new[] { CodeGen.Debug };
foreach (var codegen in codegens)
if (BuildUtils.IsHostWindows())
var config = new NativeProgramConfiguration(codegen, toolchain, lump: true);
var toolchain = ToolChain.Store.Windows().VS2019().Sdk_17134().x64();
foreach (var codegen in codegens)
{
var config = new NativeProgramConfiguration(codegen, toolchain, lump: true);
var builtNP = np.SetupSpecificConfiguration(config, toolchain.DynamicLibraryFormat)
.DeployTo("build");
builtNP.DeployTo("../Samples/UIWidgetsSamples_2019_4/Assets/Plugins/x86_64");
}
}
else if (BuildUtils.IsHostMac())
{
var toolchain = ToolChain.Store.Host();
var validConfigurations = new List<NativeProgramConfiguration>();
foreach (var codegen in codegens)
{
var config = new NativeProgramConfiguration(codegen, toolchain, lump: true);
validConfigurations.Add(config);
var builtNP = np.SetupSpecificConfiguration(config, toolchain.DynamicLibraryFormat)
.DeployTo("build");
var builtNP = np.SetupSpecificConfiguration(config, toolchain.DynamicLibraryFormat).DeployTo("build");
builtNP.DeployTo("../Samples/UIWidgetsSamples_2019_4/Assets/Plugins/x86_64");
builtNP.DeployTo("../Samples/UIWidgetsSamples_2019_4/Assets/Plugins/osx");
}
np.ValidConfigurations = validConfigurations;
return np;
}

np.Defines.Add(new[]
np.Defines.Add(c => IsWindows(c), new[]
{
// gn desc out\host_debug_unopt\ //flutter/fml:fml_lib defines
"USE_OPENSSL=1",

"FLUTTER_JIT_RUNTIME=1",
});
np.Defines.Add(c => IsMac(c), new []
{
"USE_OPENSSL=1",
"__STDC_CONSTANT_MACROS",
"__STDC_FORMAT_MACROS",
"_FORTIFY_SOURCE=2",
"_LIBCPP_DISABLE_AVAILABILITY=1",
"_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
"_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS",
"_DEBUG",
"FLUTTER_RUNTIME_MODE_DEBUG=1",
"FLUTTER_RUNTIME_MODE_PROFILE=2",
"FLUTTER_RUNTIME_MODE_RELEASE=3",
"FLUTTER_RUNTIME_MODE_JIT_RELEASE=4",
"FLUTTER_RUNTIME_MODE=1",
"FLUTTER_JIT_RUNTIME=1"
});
np.Libraries.Add(c =>
{
var basePath = flutterRoot + "/out/host_debug_unopt";
var fmlLibPath = flutterRoot + "/out/host_debug_unopt";
np.Libraries.Add(c => IsWindows(c), c => {
new StaticLibrary(basePath + "/obj/flutter/fml/fml_lib.lib"),
new StaticLibrary(fmlLibPath + "/obj/flutter/fml/fml_lib.lib"),
np.Libraries.Add(c => IsMac(c), c => {
return new PrecompiledLibrary[]
{
new StaticLibrary(fmlLibPath + "/obj/flutter/fml/libfml_lib.a"),
new SystemFramework("Foundation"),
};
});
np.Defines.Add(new[]
np.Defines.Add(c => IsWindows(c), new[]
{
// bin\gn desc out\Debug\ //:skia defines
"SK_ENABLE_SPIRV_VALIDATION",

"EGLAPI=",
});
np.Defines.Add(c => IsMac(c), new[]
{
// bin\gn desc out\Debug\ //:skia defines
"SK_ENABLE_SPIRV_VALIDATION",
"SK_ASSUME_GL=1",
"SK_ENABLE_API_AVAILABLE",
"SK_GAMMA_APPLY_TO_A8",
"GR_OP_ALLOCATE_USE_NEW",
"SK_ALLOW_STATIC_GLOBAL_INITIALIZERS=1",
"GR_TEST_UTILS=1",
"SKIA_IMPLEMENTATION=1",
"SK_GL",
"SK_ENABLE_DUMP_GPU",
"SK_SUPPORT_PDF",
"SK_CODEC_DECODES_JPEG",
"SK_ENCODE_JPEG",
"SK_ENABLE_ANDROID_UTILS",
"SK_USE_LIBGIFCODEC",
"SK_HAS_HEIF_LIBRARY",
"SK_CODEC_DECODES_PNG",
"SK_ENCODE_PNG",
"SK_CODEC_DECODES_RAW",
"SK_ENABLE_SKSL_INTERPRETER",
"SKVM_JIT_WHEN_POSSIBLE",
"SK_CODEC_DECODES_WEBP",
"SK_ENCODE_WEBP",
"SK_XML"
});
np.IncludeDirectories.Add(skiaRoot + "/third_party/externals/angle2/include");
np.IncludeDirectories.Add(c => IsWindows(c), skiaRoot + "/third_party/externals/angle2/include");
// np.IncludeDirectories.Add(skiaRoot + "/include/third_party/vulkan");
np.Libraries.Add(IsWindows, c =>

};
});
np.Libraries.Add(IsMac, c => {
var basePath = skiaRoot + "/out/Debug";
return new PrecompiledLibrary[]
{
new StaticLibrary(basePath + "/libskia.a"),
new StaticLibrary(basePath + "/libskottie.a"),
new StaticLibrary(basePath + "/libsksg.a"),
new StaticLibrary(basePath + "/libskshaper.a"),
new SystemFramework("ApplicationServices"),
new SystemFramework("OpenGL"),
new SystemFramework("AppKit"),
new SystemFramework("CoreVideo"),
};
});
np.SupportFiles.Add(
new DeployableFile(basePath + "/libEGL.dll"),
new DeployableFile(basePath + "/libEGL.dll.pdb"),
new DeployableFile(basePath + "/libGLESv2.dll"),
new DeployableFile(basePath + "/libGLESv2.dll.pdb")
np.SupportFiles.Add(c => IsWindows(c), new [] {
new DeployableFile(basePath + "/libEGL.dll"),
new DeployableFile(basePath + "/libEGL.dll.pdb"),
new DeployableFile(basePath + "/libGLESv2.dll"),
new DeployableFile(basePath + "/libGLESv2.dll.pdb"),
}
);
}

SetupTxtDependency(txtLib);
var ignoreWarnigs = new string[] { "4091", "4722", "4312", "4838", "4172", "4005", "4311", "4477" }; // todo comparing the list with engine
txtLib.CompilerSettings().Add(c => IsMac(c), c => c.WithCppLanguageVersion(CppLanguageVersion.Cpp17));
txtLib.CompilerSettings().Add(c => IsMac(c), c => c.WithCustomFlags(new []{"-Wno-c++11-narrowing"}));
txtLib.Defines.Add(c => c.CodeGen == CodeGen.Debug,
new[] { "_ITERATOR_DEBUG_LEVEL=2", "_HAS_ITERATOR_DEBUGGING=1", "_SECURE_SCL=1" });

sources = sources.Select(p => txtPath.Combine(p));
txtLib.Sources.Add(sources);
txtLib.Sources.Add(c => IsWindows(c), txtPath.Combine(new NPath("src/txt/platform_windows.cc")));
txtLib.Sources.Add(c => IsMac(c), txtPath.Combine(new NPath("src/txt/platform_mac.mm")));
txtLib.NonLumpableFiles.Add(sources);
np.Libraries.Add(txtLib);

"RAPIDJSON_HAS_CXX11_RVALUE_REFS",
"RAPIDJSON_HAS_CXX11_TYPETRAITS",
"RAPIDJSON_HAS_CXX11_NOEXCEPT"
});
np.Defines.Add(c => IsMac(c), new[]
{
"USE_OPENSSL=1",
"__STDC_CONSTANT_MACROS",
"__STDC_FORMAT_MACROS",
"_FORTIFY_SOURCE=2",
"_LIBCPP_DISABLE_AVAILABILITY=1",
"_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
"_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS",
"_DEBUG"
});
np.IncludeDirectories.Add(flutterRoot + "/third_party/rapidjson/include");

101
engine/README.md


This is the engine code of UIWidgets.
## How to Build Depedencies (Windows)
## How to Build (Windows)
### Build Skia

ninja -C .\out\host_debug_unopt\ flutter/fml:fml_lib
```
## Create symbolic
### Create symbolic
cmd
```

Flutter engine txt include skia header in this pattern 'third_party/skia/*', so without symbolic, the txt lib will include skia
header file in flutter engine, instead of headers in skia repo.
## How to Build Engine
### Build Engine
cd <uiwidigets_dir>\engine
## How to Build (Mac)
### Install Depot_tools
```
git clone 'https://chromium.googlesource.com/chromium/tools/depot_tools.git'
export PATH="${PWD}/depot_tools:${PATH}"
```
### Build Skia
```
git clone https://skia.googlesource.com/skia.git
git checkout chrome/m85
bin/gn gen out/Debug
python tools/git-sync-deps
ninja -C out/Debug -k 0
```
Please ensure that you are using python2 when executing "python tools/git-sync-deps".
### Build Flutter Engine
Setting up the Engine development environment
Please follow https://github.com/flutter/flutter/wiki/Setting-up-the-Engine-development-environment.
Check out repo and update dependencies:
```
git checkout flutter-1.17-candidate.5
gclient sync -D
```
Apply changes to BUILD.gn (src/flutter/fml/BUILD.gn)
```
diff --git a/fml/BUILD.gn b/fml/BUILD.gn
index 9b5626e78..da1322ce5 100644
--- a/fml/BUILD.gn
+++ b/fml/BUILD.gn
@@ -295,3 +295,10 @@ executable("fml_benchmarks") {
"//flutter/runtime:libdart",
]
}
+
+static_library("fml_lib") {
+ complete_static_lib = true
+ deps = [
+ "//flutter/fml",
+ ]
+}
```
Comiple engine:
```
cd engine/src
./flutter/tools/gn --unoptimized
ninja -C ./out/host_debug_unopt/ flutter/fml:fml_lib
```
If the compilation fails because "no available Mac SDK is found" (in flutter-1.17 the build tool will only try to find Mac 10.XX SDKs), please modify the file "/src/build/Mac/find_sdk.py" under flutter root by setting "sdks" as your current sdk, e.g., ['11.0'].
### Build Lib
set SKIA_ROOT and FLUTTER_ROOT to your $PATH. SKIA_ROOT is the root folder of your skia repository. FLUTTER_ROOT is the root folder of your flutter engine repository.
Create symbolic as follows. Flutter engine txt include skia header in this pattern 'third_party/skia/*', so without symbolic, the txt lib will include skia
header file in flutter engine, instead of headers in skia repo.
cmd
```
cd <uiwidigets_dir>\engine
cd third_party   \\ create the directory if not exists
ln -s <SKIA_ROOT> skia
```
### Build Engine
```
cd <uiwidigets_dir>\engine
mono bee.exe
```

90
engine/src/engine.cc


#include <assert.h>
#include "Unity/IUnityGraphics.h"
#include "Unity/IUnityUIWidgets.h"
#include "include/core/SkSurface.h"
#include "include/gpu/GrBackendSurface.h"
#include "render_api.h"
static IUnityInterfaces* s_UnityInterfaces = NULL;
static IUnityGraphics* s_Graphics = NULL;
static UnityGfxRenderer s_DeviceType = kUnityGfxRendererNull;
static RenderAPI* s_CurrentAPI = NULL;
static void UNITY_INTERFACE_API
OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType) {
if (eventType == kUnityGfxDeviceEventInitialize) {
assert(s_CurrentAPI == NULL);
s_DeviceType = s_Graphics->GetRenderer();
s_CurrentAPI = CreateRenderAPI(s_DeviceType);
}
if (s_CurrentAPI) {
s_CurrentAPI->ProcessDeviceEvent(eventType, s_UnityInterfaces);
}
if (eventType == kUnityGfxDeviceEventShutdown) {
delete s_CurrentAPI;
s_CurrentAPI = NULL;
s_DeviceType = kUnityGfxRendererNull;
}
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
UnityPluginLoad(IUnityInterfaces* unityInterfaces) {
uiwidgets::UIWidgetsSystem::GetInstancePtr()->BindUnityInterfaces(unityInterfaces);

uiwidgets::UIWidgetsSystem::GetInstancePtr()->UnBindUnityInterfaces();
}
// --------------------------------------------------------------------------
// SetTextureFromUnity, an example function we export which is called by one of
// the scripts.
extern "C" UNITY_INTERFACE_EXPORT void* UNITY_INTERFACE_API
CreateTexture(int w, int h) {
if (s_CurrentAPI == NULL) {
return NULL;
}
return s_CurrentAPI->CreateTexture(w, h);
}
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API
CreateTexture1(void *ptr, int w, int h) {
if (s_CurrentAPI == NULL) {
return;
}
s_CurrentAPI->CreateTexture1(ptr, w, h);
}
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API
SetImageTexture(void *ptr) {
if (s_CurrentAPI == NULL) {
return;
}
return s_CurrentAPI->SetImageTexture(ptr);
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API Draw123() {
if (s_CurrentAPI == NULL) {
return;
}
s_CurrentAPI->Draw();
}
static void UNITY_INTERFACE_API OnRenderEvent(int eventID) {
// Unknown / unsupported graphics device type? Do nothing
if (s_CurrentAPI == NULL) {
return;
}
if (eventID == 1) {
s_CurrentAPI->Draw();
} else if (eventID == 2) {
s_CurrentAPI->PreDraw();
} else if (eventID == 3) {
s_CurrentAPI->PostDraw();
}
}
extern "C" UnityRenderingEvent UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
GetRenderEventFunc() {
return OnRenderEvent;
}

2
engine/src/lib/ui/text/asset_manager_font_provider.cc


#pragma once
#include "asset_manager_font_provider.h"
#include "flutter/fml/logging.h"

2
engine/src/lib/ui/text/font_collection.cc


#pragma once
#include "font_collection.h"
#include <mutex>

2
engine/src/lib/ui/text/icu_util.cc


#pragma once
#include "icu_util.h"
#include <memory>

1
engine/src/lib/ui/text/paragraph.cc


#pragma once
#include "paragraph.h"
namespace uiwidgets {

1
engine/src/lib/ui/text/paragraph_builder.cc


#pragma once
#include "paragraph_builder.h"
#include "lib/ui/ui_mono_state.h"

4
engine/src/lib/ui/window/pointer_data.h


kPointerButtonStylusSecondary = 1 << 2,
};
#ifdef UIWIDGETS_FORCE_ALIGNAS_8
struct alignas(8) PointerData {
#else
#endif
enum class Change : int64_t {
kCancel,
kAdd,

10
engine/src/runtime/mono_api.cc


#include "mono_isolate.h"
#include "mono_state.h"
#ifdef __APPLE__
//https://stackoverflow.com/questions/28188258/how-do-i-get-the-current-pthread-id/28212486
const uint64_t GetCurrentThreadId() {
uint64_t tid;
pthread_threadid_np(NULL, &tid);
return tid;
}
#endif
namespace uiwidgets {

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


#pragma once
#include <windows.h>
#include <chrono>
#include <deque>
#include <functional>

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


#pragma once
#include <flutter/fml/closure.h>
#include <chrono>
#include <cstdarg>
#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 printf_console(const char* log, ...) {
va_list vl;
va_start(vl, log);
unity_uiwidgets_->printf_consolev(log, vl);
va_end(vl);
}
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
#ifdef __APPLE__
#include "shell/platform/unity/darwin/macos/uiwidgets_system.h"
#elif _WIN64
#include "shell/platform/unity/windows/uiwidgets_system.h"
#endif

4
engine/third_party/Unity/IUnityUIWidgets.h


#pragma once
#ifdef __APPLE__
#import "stdarg.h"
#endif
#include "IUnityGraphics.h"
#include "IUnityInterface.h"

2
engine/src/shell/platform/unity/windows/uiwidgets_panel.h


#include <flutter/fml/memory/ref_counted.h>
#include "gfx_worker_task_runner.h"
#include "shell/platform/unity/gfx_worker_task_runner.h"
#include "runtime/mono_api.h"
#include "unity_surface_manager.h"
#include "win32_task_runner.h"

106
engine/src/shell/platform/unity/darwin/macos/cocoa_task_runner.cc


#include "cocoa_task_runner.h"
#include <flutter/fml/time/time_point.h>
#include <atomic>
#include <utility>
namespace uiwidgets {
CocoaTaskRunner::CocoaTaskRunner(const TaskExpiredCallback& on_task_expired)
: on_task_expired_(std::move(on_task_expired)) {}
CocoaTaskRunner::~CocoaTaskRunner() = default;
std::chrono::nanoseconds CocoaTaskRunner::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();
}
}
for (const auto& observer : task_observers_) {
observer.second();
}
// 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());
}
}
CocoaTaskRunner::TaskTimePoint CocoaTaskRunner::TimePointFromUIWidgetsTime(
uint64_t uiwidgets_target_time_nanos) {
const auto fml_now = fml::TimePoint::Now().ToEpochDelta().ToNanoseconds();
if (uiwidgets_target_time_nanos <= fml_now) {
return {};
}
const auto uiwidgets_duration = uiwidgets_target_time_nanos - fml_now;
const auto now = TaskTimePoint::clock::now();
return now + std::chrono::nanoseconds(uiwidgets_duration);
}
void CocoaTaskRunner::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);
}
}
void CocoaTaskRunner::AddTaskObserver(intptr_t key,
const fml::closure& callback) {
task_observers_[key] = callback;
}
void CocoaTaskRunner::RemoveTaskObserver(intptr_t key) {
task_observers_.erase(key);
}
} // namespace uiwidgets

66
engine/src/shell/platform/unity/darwin/macos/cocoa_task_runner.h


#pragma once
#include <flutter/fml/closure.h>
#include <chrono>
#include <deque>
#include <map>
#include <mutex>
#include <queue>
#include "shell/platform/embedder/embedder.h"
#include <flutter/fml/memory/ref_counted.h>
#include "runtime/mono_api.h"
namespace uiwidgets {
class CocoaTaskRunner {
public:
using TaskExpiredCallback = std::function<void(const UIWidgetsTask*)>;
CocoaTaskRunner(const TaskExpiredCallback& on_task_expired);
~CocoaTaskRunner();
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(CocoaTaskRunner);
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;
}
};
};
TaskExpiredCallback on_task_expired_;
std::mutex task_queue_mutex_;
std::priority_queue<Task, std::deque<Task>, Task::Comparer> task_queue_;
using TaskObservers = std::map<intptr_t, fml::closure>;
TaskObservers task_observers_;
static TaskTimePoint TimePointFromUIWidgetsTime(
uint64_t uiwidgets_target_time_nanos);
};
} // namespace uiwidgets

105
engine/src/shell/platform/unity/darwin/macos/uiwidgets_panel.h


#pragma once
#include <mutex>
#include <queue>
#include <map>
#include <flutter/fml/memory/ref_counted.h>
#include "shell/platform/unity/gfx_worker_task_runner.h"
#include "runtime/mono_api.h"
#include "cocoa_task_runner.h"
#include "unity_surface_manager.h"
namespace uiwidgets {
struct MouseState {
bool state_is_down = false;
bool state_is_added = false;
uint64_t buttons = 0;
};
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(size_t width, size_t height, float device_pixel_ratio, const char* streaming_assets_path, const char* settings);
void MonoEntrypoint();
void OnDisable();
void* OnRenderTexture(size_t width, size_t height,
float dpi);
bool ReleaseNativeRenderTexture();
int RegisterTexture(void* native_texture_ptr);
void UnregisterTexture(int texture_id);
std::chrono::nanoseconds ProcessMessages();
void ProcessVSync();
void VSyncCallback(intptr_t baton);
void OnMouseMove(float x, float y);
void OnMouseDown(float x, float y, int button);
void OnMouseUp(float x, float y, int button);
void OnMouseLeave();
private:
UIWidgetsPanel(Mono_Handle handle, EntrypointCallback entrypoint_callback);
void CreateInternalUIWidgetsEngine(size_t width, size_t height, float device_pixel_ratio, const char* streaming_assets_path, const char* settings);
MouseState GetMouseState() { return mouse_state_; }
void ResetMouseState() { mouse_state_ = MouseState(); }
void SetMouseStateDown(bool is_down) { mouse_state_.state_is_down = is_down; }
void SetMouseStateAdded(bool is_added) {
mouse_state_.state_is_added = is_added;
}
void SetMouseButtons(uint64_t buttons) { mouse_state_.buttons = buttons; }
void SendMouseMove(float x, float y);
void SendMouseDown(float x, float y);
void SendMouseUp(float x, float y);
void SendMouseLeave();
void SetEventPhaseFromCursorButtonState(UIWidgetsPointerEvent* event_data);
void SendPointerEventWithData(const UIWidgetsPointerEvent& event_data);
Mono_Handle handle_;
EntrypointCallback entrypoint_callback_;
std::unique_ptr<UnitySurfaceManager> surface_manager_;
std::unique_ptr<GfxWorkerTaskRunner> gfx_worker_task_runner_;
std::unique_ptr<CocoaTaskRunner> task_runner_;
UIWidgetsEngine engine_ = nullptr;
std::vector<intptr_t> vsync_batons_;
MouseState mouse_state_;
bool process_events_ = false;
};
} // namespace uiwidgets

448
engine/src/shell/platform/unity/darwin/macos/uiwidgets_panel.mm


#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 "shell/platform/embedder/embedder.h"
#include "shell/common/switches.h"
#include "uiwidgets_system.h"
#include "uiwidgets_panel.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(size_t width, size_t height, float device_pixel_ratio,
const char* streaming_assets_path, const char* settings)
{
surface_manager_ = std::make_unique<UnitySurfaceManager>(
UIWidgetsSystem::GetInstancePtr()->GetUnityInterfaces());
void* metal_tex = surface_manager_->CreateRenderTexture(width, height);
CreateInternalUIWidgetsEngine(width, height, device_pixel_ratio, streaming_assets_path, settings);
return metal_tex;
}
void UIWidgetsPanel::CreateInternalUIWidgetsEngine(size_t width, size_t height, float device_pixel_ratio,
const char* streaming_assets_path, const char* settings)
{
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;
}
});
//render task runner configs
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);
};
//renderer config
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_->ClearCurrentContext();
};
config.open_gl.make_current = [](void* user_data) -> bool {
auto* panel = static_cast<UIWidgetsPanel*>(user_data);
return panel->surface_manager_->MakeCurrentContext();
};
config.open_gl.make_resource_current = [](void* user_data) -> bool {
auto* panel = static_cast<UIWidgetsPanel*>(user_data);
return panel->surface_manager_->MakeCurrentResourceContext();
};
config.open_gl.fbo_callback = [](void* user_data) -> uint32_t {
auto* panel = static_cast<UIWidgetsPanel*>(user_data);
return panel->surface_manager_->GetFbo();
};
config.open_gl.present = [](void* user_data) -> bool { return true; };
config.open_gl.fbo_reset_after_present = true;
//main thread task runner
task_runner_ = std::make_unique<CocoaTaskRunner>(
[this](const auto* task) {
if (UIWidgetsEngineRunTask(engine_, task) != kSuccess) {
std::cerr << "Could not post an engine task." << std::endl;
}
});
UIWidgetsTaskRunnerDescription main_task_runner = {};
main_task_runner.struct_size = sizeof(UIWidgetsTaskRunnerDescription);
main_task_runner.identifier = 2;
main_task_runner.user_data = task_runner_.get();
main_task_runner.runs_task_on_current_thread_callback = [](void* user_data) -> bool {
return [[NSThread currentThread] isMainThread];
};
main_task_runner.post_task_callback = [](UIWidgetsTask task, uint64_t target_time_nanos,
void* user_data) -> void {
static_cast<CocoaTaskRunner*>(user_data)->PostTask(task, target_time_nanos);
};
//setup custom task runners
UIWidgetsCustomTaskRunners custom_task_runners = {};
custom_task_runners.struct_size = sizeof(UIWidgetsCustomTaskRunners);
custom_task_runners.platform_task_runner = &main_task_runner;
custom_task_runners.ui_task_runner = &main_task_runner;
custom_task_runners.render_task_runner = &render_task_runner;
UIWidgetsProjectArgs args = {};
args.struct_size = sizeof(UIWidgetsProjectArgs);
args.assets_path = streaming_assets_path;
args.font_asset = settings;
//TODO: not support icu yet
//args.icu_mapper = GetICUStaticMapping;
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);
process_events_ = true;
}
void UIWidgetsPanel::MonoEntrypoint() { entrypoint_callback_(handle_); }
void UIWidgetsPanel::OnDisable() {
// drain pending messages
ProcessMessages();
// drain pending vsync batons
ProcessVSync();
process_events_ = false;
UIWidgetsSystem::GetInstancePtr()->UnregisterPanel(this);
if (engine_) {
UIWidgetsEngineShutdown(engine_);
engine_ = nullptr;
}
gfx_worker_task_runner_ = nullptr;
task_runner_ = nullptr;
//release all resources
if (surface_manager_)
{
surface_manager_->ReleaseNativeRenderTexture();
surface_manager_ = nullptr;
}
}
void* UIWidgetsPanel::OnRenderTexture(size_t width,
size_t height, float device_pixel_ratio) {
ViewportMetrics metrics;
metrics.physical_width = static_cast<float>(width);
metrics.physical_height = static_cast<float>(height);
metrics.device_pixel_ratio = device_pixel_ratio;
reinterpret_cast<EmbedderEngine*>(engine_)->SetViewportMetrics(metrics);
return surface_manager_->CreateRenderTexture(width, height);
}
bool UIWidgetsPanel::ReleaseNativeRenderTexture() { return surface_manager_->ReleaseNativeRenderTexture(); }
int UIWidgetsPanel::RegisterTexture(void* native_texture_ptr) {
//TODO: add implementation
return 0;
}
void UIWidgetsPanel::UnregisterTexture(int texture_id) {
//TODO: add implementation
}
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);
}
void UIWidgetsPanel::SetEventPhaseFromCursorButtonState(
UIWidgetsPointerEvent* event_data) {
MouseState state = GetMouseState();
event_data->phase = state.buttons == 0
? state.state_is_down ? UIWidgetsPointerPhase::kUp
: UIWidgetsPointerPhase::kHover
: state.state_is_down ? UIWidgetsPointerPhase::kMove
: UIWidgetsPointerPhase::kDown;
}
void UIWidgetsPanel::SendMouseMove(float x, float y) {
UIWidgetsPointerEvent event = {};
event.x = x;
event.y = y;
SetEventPhaseFromCursorButtonState(&event);
SendPointerEventWithData(event);
}
void UIWidgetsPanel::SendMouseDown(float x, float y) {
UIWidgetsPointerEvent event = {};
SetEventPhaseFromCursorButtonState(&event);
event.x = x;
event.y = y;
SendPointerEventWithData(event);
SetMouseStateDown(true);
}
void UIWidgetsPanel::SendMouseUp(float x, float y) {
UIWidgetsPointerEvent event = {};
SetEventPhaseFromCursorButtonState(&event);
event.x = x;
event.y = y;
SendPointerEventWithData(event);
if (event.phase == UIWidgetsPointerPhase::kUp) {
SetMouseStateDown(false);
}
}
void UIWidgetsPanel::SendMouseLeave() {
UIWidgetsPointerEvent event = {};
event.phase = UIWidgetsPointerPhase::kRemove;
SendPointerEventWithData(event);
}
void UIWidgetsPanel::SendPointerEventWithData(
const UIWidgetsPointerEvent& event_data) {
MouseState mouse_state = GetMouseState();
// If sending anything other than an add, and the pointer isn't already added,
// synthesize an add to satisfy Flutter's expectations about events.
if (!mouse_state.state_is_added &&
event_data.phase != UIWidgetsPointerPhase::kAdd) {
UIWidgetsPointerEvent event = {};
event.phase = UIWidgetsPointerPhase::kAdd;
event.x = event_data.x;
event.y = event_data.y;
event.buttons = 0;
SendPointerEventWithData(event);
}
// Don't double-add (e.g., if events are delivered out of order, so an add has
// already been synthesized).
if (mouse_state.state_is_added &&
event_data.phase == UIWidgetsPointerPhase::kAdd) {
return;
}
UIWidgetsPointerEvent event = event_data;
event.device_kind = kUIWidgetsPointerDeviceKindMouse;
event.buttons = mouse_state.buttons;
// Set metadata that's always the same regardless of the event.
event.struct_size = sizeof(event);
event.timestamp =
std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count();
UIWidgetsEngineSendPointerEvent(engine_, &event, 1);
if (event_data.phase == UIWidgetsPointerPhase::kAdd) {
SetMouseStateAdded(true);
} else if (event_data.phase == UIWidgetsPointerPhase::kRemove) {
SetMouseStateAdded(false);
ResetMouseState();
}
}
void UIWidgetsPanel::OnMouseMove(float x, float y) {
if (process_events_) {
SendMouseMove(x, y);
}
}
static uint64_t ConvertToUIWidgetsButton(int button) {
switch (button) {
case -1:
return kUIWidgetsPointerButtonMousePrimary;
case -2:
return kUIWidgetsPointerButtonMouseSecondary;
case -3:
return kUIWidgetsPointerButtonMouseMiddle;
}
std::cerr << "Mouse button not recognized: " << button << std::endl;
return 0;
}
void UIWidgetsPanel::OnMouseDown(float x, float y, int button) {
if (process_events_) {
uint64_t uiwidgets_button = ConvertToUIWidgetsButton(button);
if (uiwidgets_button != 0) {
uint64_t mouse_buttons = GetMouseState().buttons | uiwidgets_button;
SetMouseButtons(mouse_buttons);
SendMouseDown(x, y);
}
}
}
void UIWidgetsPanel::OnMouseUp(float x, float y, int button) {
if (process_events_) {
uint64_t uiwidgets_button = ConvertToUIWidgetsButton(button);
if (uiwidgets_button != 0) {
uint64_t mouse_buttons = GetMouseState().buttons & ~uiwidgets_button;
SetMouseButtons(mouse_buttons);
SendMouseUp(x, y);
}
}
}
void UIWidgetsPanel::OnMouseLeave() {
if (process_events_) {
SendMouseLeave();
}
}
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,
size_t width, size_t height, float device_pixel_ratio,
const char* streaming_assets_path,
const char* settings) {
return panel->OnEnable(width, height, device_pixel_ratio,
streaming_assets_path, settings);
}
UIWIDGETS_API(void) UIWidgetsPanel_onDisable(UIWidgetsPanel* panel) {
panel->OnDisable();
}
UIWIDGETS_API(bool) UIWidgetsPanel_releaseNativeTexture(UIWidgetsPanel* panel) {
return panel->ReleaseNativeRenderTexture();
}
UIWIDGETS_API(void*)
UIWidgetsPanel_onRenderTexture(UIWidgetsPanel* panel,
int width, int height, float dpi) {
return panel->OnRenderTexture(width, height, dpi);
}
UIWIDGETS_API(int)
UIWidgetsPanel_registerTexture(UIWidgetsPanel* panel,
void* native_texture_ptr) {
return panel->RegisterTexture(native_texture_ptr);
}
UIWIDGETS_API(void)
UIWidgetsPanel_unregisterTexture(UIWidgetsPanel* panel, int texture_id) {
panel->UnregisterTexture(texture_id);
}
UIWIDGETS_API(void)
UIWidgetsPanel_onMouseDown(UIWidgetsPanel* panel, float x, float y,
int button) {
panel->OnMouseDown(x, y, button);
}
UIWIDGETS_API(void)
UIWidgetsPanel_onMouseUp(UIWidgetsPanel* panel, float x, float y, int button) {
panel->OnMouseUp(x, y, button);
}
UIWIDGETS_API(void)
UIWidgetsPanel_onMouseMove(UIWidgetsPanel* panel, float x, float y) {
panel->OnMouseMove(x, y);
}
UIWIDGETS_API(void)
UIWidgetsPanel_onMouseLeave(UIWidgetsPanel* panel) { panel->OnMouseLeave(); }
} // namespace uiwidgets

76
engine/src/shell/platform/unity/darwin/macos/uiwidgets_system.h


#pragma once
#include <flutter/fml/closure.h>
#include <chrono>
#include <cstdarg>
#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 printf_console(const char* log, ...) {
va_list vl;
va_start(vl, log);
unity_uiwidgets_->printf_consolev(log, vl);
va_end(vl);
}
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

94
engine/src/shell/platform/unity/darwin/macos/uiwidgets_system.mm


#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) {
Update();
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);
//TODO: find a proper api similar to MsgWaitForMultipleObjects on Windows
// which will notify os to wait for the given period of time
}
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();
}
}
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

49
engine/src/shell/platform/unity/darwin/macos/unity_surface_manager.h


#pragma once
#include <OpenGL/gl3.h>
#include <AppKit/AppKit.h>
#include <Metal/Metal.h>
#include <CoreVideo/CoreVideo.h>
#include "Unity/IUnityInterface.h"
#include "flutter/fml/macros.h"
namespace uiwidgets {
class UnitySurfaceManager {
public:
UnitySurfaceManager(IUnityInterfaces* unity_interfaces);
~UnitySurfaceManager();
void* CreateRenderTexture(size_t width, size_t height);
void ReleaseNativeRenderContext();
bool ReleaseNativeRenderTexture();
bool ClearCurrentContext();
bool MakeCurrentContext();
bool MakeCurrentResourceContext();
uint32_t GetFbo();
private:
//pixel buffer handles
CVPixelBufferRef pixelbuffer_ref = nullptr;
//openGL handlers
NSOpenGLContext *gl_context_ = NULL;
NSOpenGLContext *gl_resource_context_ = NULL;
GLuint default_fbo_ = 0;
GLuint gl_tex_ = 0;
CVOpenGLTextureCacheRef gl_tex_cache_ref_ = nullptr;
CVOpenGLTextureRef gl_tex_ref_ = nullptr;
//metal handlers
id<MTLDevice> metal_device_;
id<MTLTexture> metal_tex_;
CVMetalTextureRef metal_tex_ref_ = nullptr;
CVMetalTextureCacheRef metal_tex_cache_ref_ = nullptr;
};
} // namespace uiwidgets

192
engine/src/shell/platform/unity/darwin/macos/unity_surface_manager.mm


#include "unity_surface_manager.h"
#include <flutter/fml/logging.h>
#include "Unity/IUnityGraphics.h"
#include "Unity/IUnityGraphicsMetal.h"
namespace uiwidgets {
UnitySurfaceManager::UnitySurfaceManager(IUnityInterfaces* unity_interfaces)
{
FML_DCHECK(metal_device_ == nullptr);
//get main gfx device (metal)
auto* graphics = unity_interfaces->Get<IUnityGraphics>();
FML_DCHECK(graphics->GetRenderer() == kUnityGfxRendererMetal);
auto* metalGraphics = unity_interfaces->Get<IUnityGraphicsMetalV1>();
metal_device_ = metalGraphics->MetalDevice();
//create opengl context
FML_DCHECK(!gl_context_);
FML_DCHECK(!gl_resource_context_);
NSOpenGLPixelFormatAttribute attrs[] =
{
NSOpenGLPFAAccelerated,
0
};
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
gl_context_ = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
gl_resource_context_ = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:gl_context_];
FML_DCHECK(gl_context_ != nullptr && gl_resource_context_ != nullptr);
}
UnitySurfaceManager::~UnitySurfaceManager() { ReleaseNativeRenderContext(); }
void* UnitySurfaceManager::CreateRenderTexture(size_t width, size_t height)
{
//Constants
const MTLPixelFormat ConstMetalViewPixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
const int ConstCVPixelFormat = kCVPixelFormatType_32BGRA;
const GLuint ConstGLInternalFormat = GL_SRGB8_ALPHA8;
const GLuint ConstGLFormat = GL_BGRA;
const GLuint ConstGLType = GL_UNSIGNED_INT_8_8_8_8_REV;
//render context must be available
FML_DCHECK(metal_device_ != nullptr && gl_context_ != nullptr && gl_resource_context_ != nullptr);
//render textures must be released already
FML_DCHECK(pixelbuffer_ref == nullptr && default_fbo_ == 0 && gl_tex_ == 0 && gl_tex_cache_ref_ == nullptr && gl_tex_ref_ == nullptr && metal_tex_ == nullptr && metal_tex_ref_ == nullptr && metal_tex_cache_ref_ == nullptr);
//create pixel buffer
auto gl_pixelformat_ = gl_context_.pixelFormat.CGLPixelFormatObj;
NSDictionary* cvBufferProperties = @{
(__bridge NSString*)kCVPixelBufferOpenGLCompatibilityKey : @YES,
(__bridge NSString*)kCVPixelBufferMetalCompatibilityKey : @YES,
};
CVReturn cvret = CVPixelBufferCreate(kCFAllocatorDefault,
width, height,
ConstCVPixelFormat,
(__bridge CFDictionaryRef)cvBufferProperties,
&pixelbuffer_ref);
FML_DCHECK(cvret == kCVReturnSuccess);
//create metal texture
cvret = CVMetalTextureCacheCreate(
kCFAllocatorDefault,
nil,
metal_device_,
nil,
&metal_tex_cache_ref_);
FML_DCHECK(cvret == kCVReturnSuccess);
cvret = CVMetalTextureCacheCreateTextureFromImage(
kCFAllocatorDefault,
metal_tex_cache_ref_,
pixelbuffer_ref, nil,
ConstMetalViewPixelFormat,
width, height,
0,
&metal_tex_ref_);
FML_DCHECK(cvret == kCVReturnSuccess);
metal_tex_ = CVMetalTextureGetTexture(metal_tex_ref_);
FML_DCHECK(metal_tex_ != nullptr);
//create opengl texture
cvret = CVOpenGLTextureCacheCreate(
kCFAllocatorDefault,
nil,
gl_context_.CGLContextObj,
gl_pixelformat_,
nil,
&gl_tex_cache_ref_);
FML_DCHECK(cvret == kCVReturnSuccess);
cvret = CVOpenGLTextureCacheCreateTextureFromImage(
kCFAllocatorDefault,
gl_tex_cache_ref_,
pixelbuffer_ref,
nil,
&gl_tex_ref_);
FML_DCHECK(cvret == kCVReturnSuccess);
gl_tex_ = CVOpenGLTextureGetName(gl_tex_ref_);
//initialize gl renderer
[gl_context_ makeCurrentContext];
glGenFramebuffers(1, &default_fbo_);
glBindFramebuffer(GL_FRAMEBUFFER, default_fbo_);
const GLenum texType = GL_TEXTURE_RECTANGLE;
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texType, gl_tex_, 0);
return (__bridge void*)metal_tex_;
}
bool UnitySurfaceManager::ClearCurrentContext()
{
[NSOpenGLContext clearCurrentContext];
return true;
}
bool UnitySurfaceManager::MakeCurrentContext()
{
[gl_context_ makeCurrentContext];
return true;
}
bool UnitySurfaceManager::MakeCurrentResourceContext()
{
[gl_resource_context_ makeCurrentContext];
return true;
}
uint32_t UnitySurfaceManager::GetFbo()
{
return default_fbo_;
}
void UnitySurfaceManager::ReleaseNativeRenderContext()
{
FML_DCHECK(gl_resource_context_);
CGLReleaseContext(gl_resource_context_.CGLContextObj);
gl_resource_context_ = nullptr;
FML_DCHECK(gl_context_);
CGLReleaseContext(gl_context_.CGLContextObj);
gl_context_ = nullptr;
FML_DCHECK(metal_device_ != nullptr);
metal_device_ = nullptr;
}
bool UnitySurfaceManager::ReleaseNativeRenderTexture()
{
//release gl resources
FML_DCHECK(default_fbo_ != 0);
glDeleteFramebuffers(1, &default_fbo_);
default_fbo_ = 0;
FML_DCHECK(gl_tex_ != 0);
glDeleteTextures(1, &gl_tex_);
gl_tex_ = 0;
CFRelease(gl_tex_cache_ref_);
gl_tex_cache_ref_ = nullptr;
CFRelease(gl_tex_ref_);
gl_tex_ref_ = nullptr;
//release metal resources
//since ARC is enabled by default, no need to release the texture
metal_tex_ = nullptr;
CFRelease(metal_tex_ref_);
metal_tex_ref_ = nullptr;
CFRelease(metal_tex_cache_ref_);
metal_tex_cache_ref_ = nullptr;
//release cv pixelbuffer
CVPixelBufferRelease(pixelbuffer_ref);
pixelbuffer_ref = nullptr;
return true;
}
} // namespace uiwidgets

76
engine/src/shell/platform/unity/windows/uiwidgets_system.h


#pragma once
#include <flutter/fml/closure.h>
#include <chrono>
#include <cstdarg>
#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 printf_console(const char* log, ...) {
va_list vl;
va_start(vl, log);
unity_uiwidgets_->printf_consolev(log, vl);
va_end(vl);
}
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

101
engine/src/tests/render_engine.cc


#include <assert.h>
#include "Unity/IUnityGraphics.h"
#include "Unity/IUnityUIWidgets.h"
#include "include/core/SkSurface.h"
#include "include/gpu/GrBackendSurface.h"
static IUnityInterfaces* s_UnityInterfaces = NULL;
static IUnityGraphics* s_Graphics = NULL;
static UnityGfxRenderer s_DeviceType = kUnityGfxRendererNull;
static RenderAPI* s_CurrentAPI = NULL;
static void UNITY_INTERFACE_API
OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType) {
if (eventType == kUnityGfxDeviceEventInitialize) {
assert(s_CurrentAPI == NULL);
s_DeviceType = s_Graphics->GetRenderer();
s_CurrentAPI = CreateRenderAPI(s_DeviceType);
}
if (s_CurrentAPI) {
s_CurrentAPI->ProcessDeviceEvent(eventType, s_UnityInterfaces);
}
if (eventType == kUnityGfxDeviceEventShutdown) {
delete s_CurrentAPI;
s_CurrentAPI = NULL;
s_DeviceType = kUnityGfxRendererNull;
}
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
UnityPluginLoad(IUnityInterfaces* unityInterfaces) {
//do nothing
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload() {
//do nothing
}
// --------------------------------------------------------------------------
// SetTextureFromUnity, an example function we export which is called by one of
// the scripts.
extern "C" UNITY_INTERFACE_EXPORT void* UNITY_INTERFACE_API
CreateTexture(int w, int h) {
if (s_CurrentAPI == NULL) {
return NULL;
}
return s_CurrentAPI->CreateTexture(w, h);
}
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API
CreateTexture1(void *ptr, int w, int h) {
if (s_CurrentAPI == NULL) {
return;
}
s_CurrentAPI->CreateTexture1(ptr, w, h);
}
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API
SetImageTexture(void *ptr) {
if (s_CurrentAPI == NULL) {
return;
}
return s_CurrentAPI->SetImageTexture(ptr);
}
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API Draw123() {
if (s_CurrentAPI == NULL) {
return;
}
s_CurrentAPI->Draw();
}
static void UNITY_INTERFACE_API OnRenderEvent(int eventID) {
// Unknown / unsupported graphics device type? Do nothing
if (s_CurrentAPI == NULL) {
return;
}
if (eventID == 1) {
s_CurrentAPI->Draw();
} else if (eventID == 2) {
s_CurrentAPI->PreDraw();
} else if (eventID == 3) {
s_CurrentAPI->PostDraw();
}
}
extern "C" UnityRenderingEvent UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
GetRenderEventFunc() {
return OnRenderEvent;
}

/engine/src/shell/platform/unity/uiwidgets_panel.cc → /engine/src/shell/platform/unity/windows/uiwidgets_panel.cc

/engine/src/shell/platform/unity/uiwidgets_panel.h → /engine/src/shell/platform/unity/windows/uiwidgets_panel.h

/engine/src/shell/platform/unity/unity_surface_manager.cc → /engine/src/shell/platform/unity/windows/unity_surface_manager.cc

/engine/src/shell/platform/unity/unity_surface_manager.h → /engine/src/shell/platform/unity/windows/unity_surface_manager.h

/engine/src/shell/platform/unity/win32_task_runner.h → /engine/src/shell/platform/unity/windows/win32_task_runner.h

/engine/src/shell/platform/unity/unity_external_texture_gl.cc → /engine/src/shell/platform/unity/windows/unity_external_texture_gl.cc

/engine/src/shell/platform/unity/unity_external_texture_gl.h → /engine/src/shell/platform/unity/windows/unity_external_texture_gl.h

/engine/src/shell/platform/unity/win32_task_runner.cc → /engine/src/shell/platform/unity/windows/win32_task_runner.cc

/engine/src/shell/platform/unity/uiwidgets_system.cc → /engine/src/shell/platform/unity/windows/uiwidgets_system.cc

/engine/src/render_api.cc → /engine/src/tests/render_api.cc

/engine/src/render_api.h → /engine/src/tests/render_api.h

/engine/src/render_api_d3d11.cc → /engine/src/tests/render_api_d3d11.cc

/engine/src/render_api_opengles.cc → /engine/src/tests/render_api_opengles.cc

/engine/src/render_api_vulkan.cc → /engine/src/tests/render_api_vulkan.cc

/engine/src/TestLoadICU.cpp → /engine/src/tests/TestLoadICU.cpp

/engine/src/TestLoadICU.h → /engine/src/tests/TestLoadICU.h

正在加载...
取消
保存