浏览代码
Merge branch 'dev_1.17.5' of github.com:Unity-Technologies/com.unity.uiwidgets into zxw/dev_ios_update_engine
/siyaoH-1.17-PlatformMessage
Merge branch 'dev_1.17.5' of github.com:Unity-Technologies/com.unity.uiwidgets into zxw/dev_ios_update_engine
/siyaoH-1.17-PlatformMessage
Xingwei Zhu
4 年前
当前提交
6470c92f
共有 38 个文件被更改,包括 2156 次插入 和 188 次删除
-
5Samples/UIWidgetsSamples_2019_4/Assets/CountDemo.cs
-
84Samples/UIWidgetsSamples_2019_4/Assets/CountDemo.unity
-
4Samples/UIWidgetsSamples_2019_4/Assets/Editor/EditorWindowSample/GalleryMain.cs
-
5Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/backdrop_demo.cs
-
12Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/demo/material/search_demo.cs
-
5Samples/UIWidgetsSamples_2019_4/Assets/UIWidgetsGallery/gallery/backdrop.cs
-
24com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs
-
66com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanelWrapper.cs
-
1com.unity.uiwidgets/Runtime/foundation/debug.cs
-
1com.unity.uiwidgets/Runtime/rendering/debug_overflow_indicator.cs
-
484engine/Build.bee.cs
-
219engine/README.md
-
16engine/src/assets/directory_asset_bundle.cc
-
1engine/src/engine.cc
-
16engine/src/flow/raster_cache.cc
-
11engine/src/lib/ui/painting/skottie.cc
-
2engine/src/lib/ui/text/paragraph.cc
-
5engine/src/runtime/mono_api.cc
-
2engine/src/shell/common/lists.cc
-
2engine/src/shell/gpu/gpu_surface_gl_delegate.cc
-
2engine/src/shell/platform/embedder/embedder_render_target.cc
-
2engine/src/shell/platform/embedder/embedder_surface_software.cc
-
2engine/src/shell/platform/unity/gfx_worker_task_runner.cc
-
4engine/src/shell/platform/unity/uiwidgets_system.h
-
4engine/src/shell/platform/unity/windows/unity_surface_manager.cc
-
45com.unity.uiwidgets/Runtime/engine2/AndroidPlatformUtil.cs
-
3com.unity.uiwidgets/Runtime/engine2/AndroidPlatformUtil.cs.meta
-
17engine/src/shell/platform/unity/android_unpack_streaming_asset.cc
-
16engine/src/shell/platform/unity/android_unpack_streaming_asset.h
-
94engine/src/shell/platform/unity/android/uiwidgets_system.cc
-
86engine/src/shell/platform/unity/android/uiwidgets_system.h
-
586engine/src/shell/platform/unity/android/uiwidgets_panel.cc
-
160engine/src/shell/platform/unity/android/unity_surface_manager.cc
-
63engine/src/shell/platform/unity/android/unity_surface_manager.h
-
113engine/src/shell/platform/unity/android/uiwidgets_panel.h
-
69engine/src/shell/platform/unity/android/android_task_runner.h
-
113engine/src/shell/platform/unity/android/android_task_runner.cc
|
|||
#if !UNITY_EDITOR && UNITY_ANDROID
|
|||
using UnityEngine; |
|||
using AOT; |
|||
using System; |
|||
using System.IO; |
|||
using System.Runtime.InteropServices; |
|||
using NativeBindings = Unity.UIWidgets.ui.NativeBindings; |
|||
namespace Unity.UIWidgets.engine2 { |
|||
public static class AndroidPlatformUtil { |
|||
[DllImport(NativeBindings.dllName)] |
|||
internal static extern void InitUnpackFile(UnpackFileCallback unpack); |
|||
|
|||
internal delegate string UnpackFileCallback(string file); |
|||
|
|||
[MonoPInvokeCallback(typeof(UnpackFileCallback))] |
|||
internal static string unpackFile(string file) { |
|||
var dir = Application.temporaryCachePath + "/"; |
|||
if (!File.Exists(dir + file)) { |
|||
WWW unpackerWWW = new WWW("jar:file://" + Application.dataPath + "!/assets/" + file); |
|||
while (!unpackerWWW.isDone) { |
|||
} // This will block in the webplayer.
|
|||
|
|||
if (!string.IsNullOrEmpty(unpackerWWW.error)) { |
|||
Debug.Log("Error unpacking 'jar:file://" + Application.dataPath + "!/assets/" + file + |
|||
"'"); |
|||
dir = ""; |
|||
return dir + file; |
|||
} |
|||
|
|||
File.WriteAllBytes(dir + file, unpackerWWW.bytes); // 64MB limit on File.WriteAllBytes.
|
|||
} |
|||
|
|||
return dir + file; |
|||
} |
|||
|
|||
[DllImport(NativeBindings.dllName)] |
|||
static extern System.IntPtr GetUnityContextEventFunc(); |
|||
|
|||
public static void Init() { |
|||
InitUnpackFile(unpackFile); |
|||
GL.IssuePluginEvent(GetUnityContextEventFunc(), 1); |
|||
} |
|||
} |
|||
} |
|||
#endif
|
|
|||
fileFormatVersion: 2 |
|||
guid: 76a442e0d2934484b6b95ed3b22889f2 |
|||
timeCreated: 1616467811 |
|
|||
#include "android_unpack_streaming_asset.h"
|
|||
#include <stdarg.h>
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
const char* AndroidUnpackStreamingAsset::Unpack(const char* file) { |
|||
return _unpack(file); |
|||
} |
|||
|
|||
UnpackFileCallback AndroidUnpackStreamingAsset::_unpack; |
|||
|
|||
UIWIDGETS_API(void) |
|||
InitUnpackFile(UnpackFileCallback _unpack) { |
|||
AndroidUnpackStreamingAsset::_unpack = _unpack; |
|||
} |
|||
|
|||
} |
|
|||
#pragma once |
|||
#include "runtime/mono_api.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
typedef const char* (*UnpackFileCallback)(const char* file); |
|||
|
|||
|
|||
class AndroidUnpackStreamingAsset{ |
|||
public: |
|||
static UnpackFileCallback _unpack; |
|||
|
|||
static const char* Unpack(const char* file); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#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
|
|
|||
#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" |
|||
#include <GLES2/gl2.h> |
|||
#include <EGL/egl.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); |
|||
// TODO: error in __android_log_vprint -> vsnprintf -> __vfprintf -> strlen_a |
|||
// 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) { |
|||
auto context = eglGetCurrentContext(); |
|||
auto display = eglGetCurrentDisplay(); |
|||
auto draw = eglGetCurrentSurface(EGL_DRAW); |
|||
auto read = eglGetCurrentSurface(EGL_READ); |
|||
GetInstancePtr()->GfxWorkerCallback(eventId, data); |
|||
eglMakeCurrent(display, draw, read, context); |
|||
} |
|||
|
|||
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 |
|
|||
#include "uiwidgets_panel.h"
|
|||
|
|||
#include <flutter/fml/synchronization/waitable_event.h>
|
|||
|
|||
#include <fstream>
|
|||
#include <iostream>
|
|||
|
|||
#include "lib/ui/window/viewport_metrics.h"
|
|||
#include "runtime/mono_api.h"
|
|||
#include "shell/common/switches.h"
|
|||
#include "shell/platform/embedder/embedder_engine.h"
|
|||
#include "uiwidgets_system.h"
|
|||
#include "third_party/Unity/IUnityGraphics.h"
|
|||
|
|||
namespace uiwidgets |
|||
{ |
|||
|
|||
fml::RefPtr<UIWidgetsPanel> UIWidgetsPanel::Create( |
|||
Mono_Handle handle, UIWidgetsWindowType window_type, EntrypointCallback entrypoint_callback) |
|||
{ |
|||
return fml::MakeRefCounted<UIWidgetsPanel>(handle, window_type, entrypoint_callback); |
|||
} |
|||
|
|||
UIWidgetsPanel::UIWidgetsPanel(Mono_Handle handle, |
|||
UIWidgetsWindowType window_type, |
|||
EntrypointCallback entrypoint_callback) |
|||
: handle_(handle), window_type_(window_type), entrypoint_callback_(entrypoint_callback) {} |
|||
|
|||
UIWidgetsPanel::~UIWidgetsPanel() = default; |
|||
|
|||
bool UIWidgetsPanel::NeedUpdateByPlayerLoop() |
|||
{ |
|||
return window_type_ == GameObjectPanel; |
|||
} |
|||
|
|||
bool UIWidgetsPanel::NeedUpdateByEditorLoop() |
|||
{ |
|||
return window_type_ == EditorWindowPanel; |
|||
} |
|||
|
|||
void UIWidgetsPanel::OnEnable(void *native_texture_ptr, 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()); |
|||
|
|||
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<CocoaTaskRunner>( |
|||
gettid(), [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<CocoaTaskRunner *>(user_data)->RunsTasksOnCurrentThread(); |
|||
}; |
|||
ui_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); |
|||
}; |
|||
|
|||
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 = streaming_assets_path; |
|||
args.font_asset = settings; |
|||
|
|||
args.icu_mapper = GetICUStaticMapping; |
|||
|
|||
// // Used for IOS build
|
|||
// // std::string icu_symbol_prefix = "_binary_icudtl_dat_start";
|
|||
// // std::string native_lib_path =
|
|||
// // "pathtodll/Plugins/x86_64/libUIWidgets_d.dll"; args.icu_mapper =
|
|||
// // [icu_symbol_prefix, native_lib_path] {
|
|||
// // return GetSymbolMapping(icu_symbol_prefix, native_lib_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); |
|||
|
|||
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; |
|||
|
|||
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 = static_cast<float>(width); |
|||
metrics.physical_height = static_cast<float>(height); |
|||
metrics.device_pixel_ratio = device_pixel_ratio; |
|||
reinterpret_cast<EmbedderEngine *>(engine_)->SetViewportMetrics(metrics); |
|||
} |
|||
|
|||
int UIWidgetsPanel::RegisterTexture(void *native_texture_ptr) |
|||
{ |
|||
std::cerr << "registering external texture is not implemented for android" << std::endl; |
|||
int texture_identifier = 0; |
|||
// texture_identifier++;
|
|||
|
|||
// auto* engine = reinterpret_cast<EmbedderEngine*>(engine_);
|
|||
|
|||
// engine->GetShell().GetPlatformView()->RegisterTexture(
|
|||
// std::make_unique<UnityExternalTextureGL>(
|
|||
// texture_identifier, native_texture_ptr, surface_manager_.get()));
|
|||
return texture_identifier; |
|||
} |
|||
|
|||
void UIWidgetsPanel::UnregisterTexture(int texture_id) |
|||
{ |
|||
std::cerr << "registering external texture is not implemented for android" << std::endl; |
|||
|
|||
auto *engine = reinterpret_cast<EmbedderEngine *>(engine_); |
|||
engine->GetShell().GetPlatformView()->UnregisterTexture(texture_id); |
|||
} |
|||
|
|||
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::OnKeyDown(int keyCode, bool isKeyDown) |
|||
{ |
|||
if (process_events_) |
|||
{ |
|||
UIWidgetsPointerEvent event = {}; |
|||
event.phase = isKeyDown ? UIWidgetsPointerPhase::kMouseDown : UIWidgetsPointerPhase::kMouseUp; |
|||
event.device_kind = |
|||
UIWidgetsPointerDeviceKind::kUIWidgetsPointerDeviceKindKeyboard; |
|||
event.buttons = keyCode; |
|||
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); |
|||
} |
|||
} |
|||
|
|||
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, int windowType, |
|||
UIWidgetsPanel::EntrypointCallback entrypoint_callback) |
|||
{ |
|||
UIWidgetsWindowType window_type = static_cast<UIWidgetsWindowType>(windowType); |
|||
const auto panel = UIWidgetsPanel::Create(handle, window_type, entrypoint_callback); |
|||
panel->AddRef(); |
|||
// entrypoint_callback(handle);
|
|||
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, |
|||
const char *streaming_assets_path, |
|||
const char *settings) |
|||
{ |
|||
panel->OnEnable(native_texture_ptr, width, height, device_pixel_ratio, |
|||
streaming_assets_path, settings); |
|||
} |
|||
|
|||
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); |
|||
} |
|||
|
|||
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_onKey(UIWidgetsPanel *panel, int keyCode, bool isKeyDown) |
|||
{ |
|||
panel->OnKeyDown(keyCode, isKeyDown); |
|||
} |
|||
|
|||
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(); } |
|||
|
|||
static void UNITY_INTERFACE_API OnGetUnityContextEvent(int eventID) |
|||
{ |
|||
UnitySurfaceManager::GetUnityContext(); |
|||
} |
|||
|
|||
// --------------------------------------------------------------------------
|
|||
// GetRenderEventFunc, an example function we export which is used to get a rendering event callback function.
|
|||
|
|||
UIWIDGETS_API(UnityRenderingEvent) |
|||
GetUnityContextEventFunc() |
|||
{ |
|||
return OnGetUnityContextEvent; |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#include "unity_surface_manager.h"
|
|||
|
|||
#include <flutter/fml/logging.h>
|
|||
#include <EGL/egl.h>
|
|||
#include <GLES2/gl2.h>
|
|||
|
|||
#include "src/shell/common/shell_io_manager.h"
|
|||
#include "src/shell/gpu/gpu_surface_delegate.h"
|
|||
#include "src/shell/gpu/gpu_surface_gl_delegate.h"
|
|||
namespace uiwidgets |
|||
{ |
|||
|
|||
static EGLDisplay egl_display_; |
|||
static EGLContext egl_unity_context_; |
|||
|
|||
template <class T> |
|||
using EGLResult = std::pair<bool, T>; |
|||
|
|||
UnitySurfaceManager::UnitySurfaceManager(IUnityInterfaces *unity_interfaces) |
|||
: egl_context_(EGL_NO_CONTEXT), |
|||
egl_resource_context_(EGL_NO_CONTEXT) |
|||
{ |
|||
initialize_succeeded_ = Initialize(unity_interfaces); |
|||
} |
|||
|
|||
UnitySurfaceManager::~UnitySurfaceManager() { CleanUp(); } |
|||
|
|||
GLuint UnitySurfaceManager::CreateRenderSurface(void *native_texture_ptr) |
|||
{ |
|||
GLint old_framebuffer_binding; |
|||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_framebuffer_binding); |
|||
|
|||
glGenFramebuffers(1, &fbo_); |
|||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
|||
|
|||
GLuint gltex = (GLuint)(size_t)(native_texture_ptr); |
|||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gltex, 0); |
|||
FML_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); |
|||
|
|||
glBindFramebuffer(GL_FRAMEBUFFER, old_framebuffer_binding); |
|||
|
|||
return fbo_; |
|||
} |
|||
|
|||
void UnitySurfaceManager::DestroyRenderSurface() |
|||
{ |
|||
FML_DCHECK(fbo_ != 0); |
|||
glDeleteFramebuffers(1, &fbo_); |
|||
fbo_ = 0; |
|||
} |
|||
|
|||
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; |
|||
} |
|||
|
|||
static EGLResult<EGLConfig> ChooseEGLConfiguration(EGLDisplay display) |
|||
{ |
|||
EGLint attributes[] = { |
|||
// clang-format off
|
|||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
|||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
|||
EGL_RED_SIZE, 8, |
|||
EGL_GREEN_SIZE, 8, |
|||
EGL_BLUE_SIZE, 8, |
|||
EGL_ALPHA_SIZE, 8, |
|||
EGL_DEPTH_SIZE, 0, |
|||
EGL_STENCIL_SIZE, 0, |
|||
EGL_NONE, // termination sentinel
|
|||
// clang-format on
|
|||
}; |
|||
|
|||
EGLint config_count = 0; |
|||
EGLConfig egl_config = nullptr; |
|||
|
|||
if (eglChooseConfig(display, attributes, &egl_config, 1, &config_count) != |
|||
EGL_TRUE) |
|||
{ |
|||
return {false, nullptr}; |
|||
} |
|||
|
|||
bool success = config_count > 0 && egl_config != nullptr; |
|||
|
|||
return {success, success ? egl_config : nullptr}; |
|||
} |
|||
|
|||
static EGLResult<EGLSurface> CreateContext(EGLDisplay display, |
|||
EGLConfig config, |
|||
EGLContext share = EGL_NO_CONTEXT) |
|||
{ |
|||
EGLint attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; |
|||
|
|||
EGLContext context = eglCreateContext(display, config, share, attributes); |
|||
|
|||
return {context != EGL_NO_CONTEXT, context}; |
|||
} |
|||
|
|||
void UnitySurfaceManager::GetUnityContext() |
|||
{ |
|||
if(egl_unity_context_ != nullptr){ |
|||
return; |
|||
} |
|||
egl_display_ = eglGetCurrentDisplay(); |
|||
egl_unity_context_ = eglGetCurrentContext(); |
|||
FML_CHECK(egl_display_ != EGL_NO_DISPLAY) |
|||
<< "Renderer type is invalid"; |
|||
} |
|||
|
|||
bool UnitySurfaceManager::Initialize(IUnityInterfaces *unity_interfaces) |
|||
{ |
|||
FML_CHECK(egl_display_ != EGL_NO_DISPLAY) |
|||
<< "Renderer type is invalid"; |
|||
|
|||
// Initialize the display connection.
|
|||
FML_CHECK(eglInitialize(egl_display_, nullptr, nullptr) == EGL_TRUE) |
|||
<< "Renderer type is invalid"; |
|||
|
|||
auto valid_ = true; |
|||
|
|||
bool success = false; |
|||
|
|||
std::tie(success, egl_config_) = ChooseEGLConfiguration(egl_display_); |
|||
FML_CHECK(success) << "Could not choose an EGL configuration."; |
|||
|
|||
std::tie(success, egl_context_) = CreateContext(egl_display_, egl_config_, egl_unity_context_); |
|||
|
|||
std::tie(success, egl_resource_context_) = CreateContext(egl_display_, egl_config_, egl_context_); |
|||
|
|||
return success; |
|||
} |
|||
|
|||
void UnitySurfaceManager::CleanUp() |
|||
{ |
|||
if (egl_display_ != EGL_NO_DISPLAY && |
|||
egl_resource_context_ != EGL_NO_CONTEXT) |
|||
{ |
|||
eglDestroyContext(egl_display_, egl_resource_context_); |
|||
egl_resource_context_ = EGL_NO_CONTEXT; |
|||
} |
|||
if (egl_display_ != EGL_NO_DISPLAY && egl_context_ != EGL_NO_CONTEXT) |
|||
{ |
|||
eglDestroyContext(egl_display_, egl_context_); |
|||
egl_context_ = EGL_NO_CONTEXT; |
|||
} |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#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 <cstdint> |
|||
|
|||
#include "Unity/IUnityInterface.h" |
|||
#include "flutter/fml/macros.h" |
|||
|
|||
#include <include/gpu/GrContext.h> |
|||
#include <src/gpu/gl/GrGLDefines.h> |
|||
|
|||
#include "cassert" |
|||
#include "include/core/SkCanvas.h" |
|||
#include "include/core/SkSurface.h" |
|||
#include "include/core/SkTextBlob.h" |
|||
#include "include/effects/SkPerlinNoiseShader.h" |
|||
#include "include/gpu/GrBackendSurface.h" |
|||
#include "include/gpu/gl/GrGLTypes.h" |
|||
|
|||
#include "Unity/IUnityGraphics.h" |
|||
|
|||
namespace uiwidgets |
|||
{ |
|||
|
|||
class UnitySurfaceManager |
|||
{ |
|||
public: |
|||
static void GetUnityContext(); |
|||
|
|||
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(); |
|||
|
|||
EGLContext egl_context_; |
|||
EGLContext egl_resource_context_; |
|||
EGLConfig egl_config_; |
|||
|
|||
bool initialize_succeeded_; |
|||
|
|||
GLuint fbo_ = 0; |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#pragma once |
|||
|
|||
#include <flutter/fml/memory/ref_counted.h> |
|||
|
|||
#include "shell/platform/unity/gfx_worker_task_runner.h" |
|||
#include "runtime/mono_api.h" |
|||
#include "unity_surface_manager.h" |
|||
#include "android_task_runner.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
enum UIWidgetsWindowType { |
|||
InvalidPanel = 0, |
|||
GameObjectPanel = 1, |
|||
EditorWindowPanel = 2 |
|||
}; |
|||
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, UIWidgetsWindowType window_type, EntrypointCallback entrypoint_callback); |
|||
|
|||
~UIWidgetsPanel(); |
|||
|
|||
void OnEnable(void* native_texture_ptr, size_t width, size_t height, |
|||
float device_pixel_ratio, const char* streaming_assets_path, |
|||
const char* settings); |
|||
|
|||
void MonoEntrypoint(); |
|||
|
|||
void OnDisable(); |
|||
|
|||
void OnRenderTexture(void* native_texture_ptr, size_t width, size_t height, |
|||
float dpi); |
|||
|
|||
int RegisterTexture(void* native_texture_ptr); |
|||
|
|||
void UnregisterTexture(int texture_id); |
|||
|
|||
std::chrono::nanoseconds ProcessMessages(); |
|||
|
|||
void ProcessVSync(); |
|||
|
|||
void VSyncCallback(intptr_t baton); |
|||
|
|||
void OnKeyDown(int keyCode, bool isKeyDown); |
|||
|
|||
void OnMouseMove(float x, float y); |
|||
|
|||
void OnMouseDown(float x, float y, int button); |
|||
|
|||
void OnMouseUp(float x, float y, int button); |
|||
|
|||
void OnMouseLeave(); |
|||
|
|||
bool NeedUpdateByPlayerLoop(); |
|||
|
|||
bool NeedUpdateByEditorLoop(); |
|||
|
|||
private: |
|||
UIWidgetsPanel(Mono_Handle handle, UIWidgetsWindowType window_type, EntrypointCallback entrypoint_callback); |
|||
|
|||
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_; |
|||
UIWidgetsWindowType window_type_; |
|||
EntrypointCallback entrypoint_callback_; |
|||
|
|||
std::unique_ptr<UnitySurfaceManager> surface_manager_; |
|||
GLuint fbo_ = 0; |
|||
|
|||
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 |
|
|||
#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(pid_t threadId, 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); |
|||
|
|||
bool RunsTasksOnCurrentThread(); |
|||
|
|||
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_; |
|||
pid_t threadId; |
|||
|
|||
using TaskObservers = std::map<intptr_t, fml::closure>; |
|||
TaskObservers task_observers_; |
|||
|
|||
static TaskTimePoint TimePointFromUIWidgetsTime( |
|||
uint64_t uiwidgets_target_time_nanos); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "android_task_runner.h"
|
|||
|
|||
#include <flutter/fml/time/time_point.h>
|
|||
|
|||
#include <atomic>
|
|||
#include <utility>
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
CocoaTaskRunner::CocoaTaskRunner(pid_t threadId, const TaskExpiredCallback& on_task_expired) |
|||
: on_task_expired_(std::move(on_task_expired)), |
|||
threadId(threadId) |
|||
{} |
|||
|
|||
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 <= (uint64_t)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); |
|||
} |
|||
} |
|||
|
|||
bool CocoaTaskRunner::RunsTasksOnCurrentThread(){ |
|||
pid_t id = gettid(); |
|||
return threadId == id; |
|||
} |
|||
|
|||
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
|
撰写
预览
正在加载...
取消
保存
Reference in new issue