siyao
4 年前
当前提交
a08b4edb
共有 14 个文件被更改,包括 1259 次插入 和 14 次删除
-
10engine/build.py
-
3engine/src/engine.cc
-
5engine/src/runtime/mono_api.cc
-
2engine/src/shell/gpu/gpu_surface_gl.cc
-
10engine/src/shell/platform/unity/gfx_worker_task_runner.cc
-
106engine/src/shell/platform/unity/darwin/android/cocoa_task_runner.cc
-
66engine/src/shell/platform/unity/darwin/android/cocoa_task_runner.h
-
504engine/src/shell/platform/unity/darwin/android/uiwidgets_panel.cc
-
103engine/src/shell/platform/unity/darwin/android/uiwidgets_panel.h
-
94engine/src/shell/platform/unity/darwin/android/uiwidgets_system.cc
-
76engine/src/shell/platform/unity/darwin/android/uiwidgets_system.h
-
239engine/src/shell/platform/unity/darwin/android/unity_surface_manager.cc
-
55engine/src/shell/platform/unity/darwin/android/unity_surface_manager.h
|
|||
#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
|
|
|||
#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 |
|
|||
#include "uiwidgets_panel.h"
|
|||
|
|||
#include <Windows.h>
|
|||
#include <flutter/fml/synchronization/waitable_event.h>
|
|||
#include <include\utils\SkBase64.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 "unity_external_texture_gl.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
fml::RefPtr<UIWidgetsPanel> UIWidgetsPanel::Create( |
|||
Mono_Handle handle, EntrypointCallback entrypoint_callback) { |
|||
return fml::MakeRefCounted<UIWidgetsPanel>(handle, entrypoint_callback); |
|||
} |
|||
|
|||
UIWidgetsPanel::UIWidgetsPanel(Mono_Handle handle, |
|||
EntrypointCallback entrypoint_callback) |
|||
: handle_(handle), entrypoint_callback_(entrypoint_callback) {} |
|||
|
|||
UIWidgetsPanel::~UIWidgetsPanel() = default; |
|||
|
|||
void UIWidgetsPanel::OnEnable(void* native_texture_ptr, size_t width, |
|||
size_t height, float device_pixel_ratio, |
|||
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<Win32TaskRunner>( |
|||
GetCurrentThreadId(), [this](const auto* task) { |
|||
if (UIWidgetsEngineRunTask(engine_, task) != kSuccess) { |
|||
std::cerr << "Could not post an engine task." << std::endl; |
|||
} |
|||
}); |
|||
|
|||
UIWidgetsTaskRunnerDescription ui_task_runner = {}; |
|||
ui_task_runner.struct_size = sizeof(UIWidgetsTaskRunnerDescription); |
|||
ui_task_runner.identifier = 2; |
|||
ui_task_runner.user_data = task_runner_.get(); |
|||
ui_task_runner.runs_task_on_current_thread_callback = |
|||
[](void* user_data) -> bool { |
|||
return static_cast<Win32TaskRunner*>(user_data)->RunsTasksOnCurrentThread(); |
|||
}; |
|||
ui_task_runner.post_task_callback = [](UIWidgetsTask task, |
|||
uint64_t target_time_nanos, |
|||
void* user_data) -> void { |
|||
static_cast<Win32TaskRunner*>(user_data)->PostTask(task, target_time_nanos); |
|||
}; |
|||
|
|||
UIWidgetsCustomTaskRunners custom_task_runners = {}; |
|||
custom_task_runners.struct_size = sizeof(UIWidgetsCustomTaskRunners); |
|||
custom_task_runners.platform_task_runner = &ui_task_runner; |
|||
custom_task_runners.ui_task_runner = &ui_task_runner; |
|||
custom_task_runners.render_task_runner = &render_task_runner; |
|||
|
|||
UIWidgetsProjectArgs args = {}; |
|||
args.struct_size = sizeof(UIWidgetsProjectArgs); |
|||
|
|||
args.assets_path = streaming_assets_path; |
|||
args.font_asset = settings; |
|||
|
|||
// std::string icu_path = std::string(streaming_assets_path) + "/icudtl.dat";
|
|||
// args.icu_data_path = icu_path.c_str();
|
|||
|
|||
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) { |
|||
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) { |
|||
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, |
|||
UIWidgetsPanel::EntrypointCallback entrypoint_callback) { |
|||
const auto panel = UIWidgetsPanel::Create(handle, entrypoint_callback); |
|||
panel->AddRef(); |
|||
return panel.get(); |
|||
} |
|||
|
|||
UIWIDGETS_API(void) UIWidgetsPanel_dispose(UIWidgetsPanel* panel) { |
|||
panel->Release(); |
|||
} |
|||
|
|||
UIWIDGETS_API(void) |
|||
UIWidgetsPanel_onEnable(UIWidgetsPanel* panel, void* native_texture_ptr, |
|||
size_t width, size_t height, float device_pixel_ratio, |
|||
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(); } |
|||
} // 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 "cocoa_task_runner.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(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(); |
|||
|
|||
private: |
|||
UIWidgetsPanel(Mono_Handle handle, 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_; |
|||
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 |
|
|||
#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" |
|||
|
|||
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 |
|
|||
#include "unity_surface_manager.h"
|
|||
|
|||
#include <d3d11.h>
|
|||
#include <dxgi.h>
|
|||
#include <flutter/fml/logging.h>
|
|||
|
|||
#include "Unity/IUnityGraphics.h"
|
|||
#include "Unity/IUnityGraphicsD3D11.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
UnitySurfaceManager::UnitySurfaceManager(IUnityInterfaces* unity_interfaces) |
|||
: egl_display_(EGL_NO_DISPLAY), |
|||
egl_context_(EGL_NO_CONTEXT), |
|||
egl_resource_context_(EGL_NO_CONTEXT), |
|||
egl_config_(nullptr) { |
|||
initialize_succeeded_ = Initialize(unity_interfaces); |
|||
} |
|||
|
|||
UnitySurfaceManager::~UnitySurfaceManager() { CleanUp(); } |
|||
|
|||
GLuint UnitySurfaceManager::CreateRenderSurface(void* native_texture_ptr) { |
|||
ID3D11Texture2D* d3d11_texture = |
|||
static_cast<ID3D11Texture2D*>(native_texture_ptr); |
|||
IDXGIResource* image_resource; |
|||
HRESULT hr = d3d11_texture->QueryInterface( |
|||
__uuidof(IDXGIResource), reinterpret_cast<void**>(&image_resource)); |
|||
FML_CHECK(SUCCEEDED(hr)) << "UnitySurfaceManager: QueryInterface() failed"; |
|||
|
|||
HANDLE shared_image_handle; |
|||
hr = image_resource->GetSharedHandle(&shared_image_handle); |
|||
FML_CHECK(SUCCEEDED(hr)) << "UnitySurfaceManager: GetSharedHandle() failed"; |
|||
|
|||
image_resource->Release(); |
|||
|
|||
FML_CHECK(shared_image_handle != nullptr) |
|||
<< "UnitySurfaceManager: shared_image_handle is nullptr, miscFlags " |
|||
"D3D11_RESOURCE_MISC_SHARED is needed"; |
|||
|
|||
IDXGIResource* dxgi_resource; |
|||
hr = d3d11_device_->OpenSharedResource( |
|||
shared_image_handle, __uuidof(ID3D11Resource), |
|||
reinterpret_cast<void**>(&dxgi_resource)); |
|||
FML_CHECK(SUCCEEDED(hr)) |
|||
<< "UnitySurfaceManager: failed to open shared resource"; |
|||
|
|||
ID3D11Texture2D* image_texture; |
|||
hr = dxgi_resource->QueryInterface(__uuidof(ID3D11Texture2D), |
|||
reinterpret_cast<void**>(&image_texture)); |
|||
FML_CHECK(SUCCEEDED(hr)) |
|||
<< "UnitySurfaceManager: failed to query interface ID3D11Texture2D"; |
|||
|
|||
dxgi_resource->Release(); |
|||
|
|||
const EGLint attribs[] = {EGL_NONE}; |
|||
FML_DCHECK(fbo_egl_image_ == nullptr); |
|||
fbo_egl_image_ = |
|||
eglCreateImageKHR(egl_display_, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE, |
|||
static_cast<EGLClientBuffer>(image_texture), attribs); |
|||
FML_CHECK(fbo_egl_image_ != EGL_NO_IMAGE_KHR); |
|||
|
|||
image_texture->Release(); |
|||
|
|||
GLint old_texture_binding_2d; |
|||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture_binding_2d); |
|||
|
|||
FML_DCHECK(fbo_texture_ == 0); |
|||
glGenTextures(1, &fbo_texture_); |
|||
glBindTexture(GL_TEXTURE_2D, fbo_texture_); |
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
|||
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, fbo_egl_image_); |
|||
glBindTexture(GL_TEXTURE_2D, old_texture_binding_2d); |
|||
|
|||
GLint old_framebuffer_binding; |
|||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_framebuffer_binding); |
|||
|
|||
FML_DCHECK(fbo_ == 0); |
|||
glGenFramebuffers(1, &fbo_); |
|||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_); |
|||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
|||
fbo_texture_, 0); |
|||
FML_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == |
|||
GL_FRAMEBUFFER_COMPLETE); |
|||
glBindFramebuffer(GL_FRAMEBUFFER, old_framebuffer_binding); |
|||
|
|||
return fbo_; |
|||
} |
|||
|
|||
void UnitySurfaceManager::DestroyRenderSurface() { |
|||
FML_DCHECK(fbo_ != 0); |
|||
glDeleteFramebuffers(1, &fbo_); |
|||
fbo_ = 0; |
|||
|
|||
FML_DCHECK(fbo_texture_ != 0); |
|||
glDeleteTextures(1, &fbo_texture_); |
|||
fbo_texture_ = 0; |
|||
|
|||
FML_DCHECK(fbo_egl_image_ != nullptr); |
|||
eglDestroyImageKHR(egl_display_, fbo_egl_image_); |
|||
fbo_egl_image_ = nullptr; |
|||
} |
|||
|
|||
bool UnitySurfaceManager::ClearCurrent() { |
|||
return eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, |
|||
EGL_NO_CONTEXT) == EGL_TRUE; |
|||
} |
|||
|
|||
bool UnitySurfaceManager::MakeCurrent(const EGLSurface surface) { |
|||
return eglMakeCurrent(egl_display_, surface, surface, egl_context_) == |
|||
EGL_TRUE; |
|||
} |
|||
|
|||
bool UnitySurfaceManager::MakeResourceCurrent() { |
|||
return eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, |
|||
egl_resource_context_) == EGL_TRUE; |
|||
} |
|||
|
|||
bool UnitySurfaceManager::Initialize(IUnityInterfaces* unity_interfaces) { |
|||
IUnityGraphics* graphics = unity_interfaces->Get<IUnityGraphics>(); |
|||
FML_CHECK(graphics->GetRenderer() == kUnityGfxRendererD3D11) |
|||
<< "Renderer type is invalid"; |
|||
|
|||
IUnityGraphicsD3D11* d3d11 = unity_interfaces->Get<IUnityGraphicsD3D11>(); |
|||
ID3D11Device* d3d11_device = d3d11->GetDevice(); |
|||
|
|||
IDXGIDevice* dxgi_device; |
|||
HRESULT hr = d3d11_device->QueryInterface( |
|||
__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgi_device)); |
|||
|
|||
FML_CHECK(SUCCEEDED(hr)) << "d3d11_device->QueryInterface(...) failed"; |
|||
|
|||
IDXGIAdapter* dxgi_adapter; |
|||
hr = dxgi_device->GetAdapter(&dxgi_adapter); |
|||
FML_CHECK(SUCCEEDED(hr)) << "dxgi_adapter->GetAdapter(...) failed"; |
|||
|
|||
dxgi_device->Release(); |
|||
|
|||
DXGI_ADAPTER_DESC adapter_desc; |
|||
hr = dxgi_adapter->GetDesc(&adapter_desc); |
|||
FML_CHECK(SUCCEEDED(hr)) << "dxgi_adapter->GetDesc(...) failed"; |
|||
|
|||
dxgi_adapter->Release(); |
|||
|
|||
EGLint displayAttribs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, |
|||
EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, |
|||
EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE, |
|||
adapter_desc.AdapterLuid.HighPart, |
|||
EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE, |
|||
adapter_desc.AdapterLuid.LowPart, |
|||
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, |
|||
EGL_TRUE, |
|||
EGL_NONE}; |
|||
|
|||
egl_display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, |
|||
EGL_DEFAULT_DISPLAY, displayAttribs); |
|||
|
|||
FML_CHECK(egl_display_ != EGL_NO_DISPLAY) |
|||
<< "EGL: Failed to get a compatible EGLdisplay"; |
|||
|
|||
if (eglInitialize(egl_display_, nullptr, nullptr) == EGL_FALSE) { |
|||
FML_CHECK(false) << "EGL: Failed to initialize EGL"; |
|||
} |
|||
|
|||
EGLAttrib egl_device = 0; |
|||
eglQueryDisplayAttribEXT(egl_display_, EGL_DEVICE_EXT, &egl_device); |
|||
EGLAttrib angle_device = 0; |
|||
eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(egl_device), |
|||
EGL_D3D11_DEVICE_ANGLE, &angle_device); |
|||
d3d11_device_ = reinterpret_cast<ID3D11Device*>(angle_device); |
|||
|
|||
const EGLint configAttributes[] = {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, |
|||
EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, |
|||
EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8, |
|||
EGL_NONE}; |
|||
|
|||
EGLint numConfigs = 0; |
|||
if (eglChooseConfig(egl_display_, configAttributes, &egl_config_, 1, |
|||
&numConfigs) == EGL_FALSE || |
|||
numConfigs == 0) { |
|||
FML_CHECK(false) << "EGL: Failed to choose first context"; |
|||
} |
|||
|
|||
const EGLint display_context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, |
|||
EGL_NONE}; |
|||
|
|||
egl_context_ = eglCreateContext(egl_display_, egl_config_, EGL_NO_CONTEXT, |
|||
display_context_attributes); |
|||
if (egl_context_ == EGL_NO_CONTEXT) { |
|||
FML_CHECK(false) << "EGL: Failed to create EGL context"; |
|||
} |
|||
|
|||
egl_resource_context_ = eglCreateContext( |
|||
egl_display_, egl_config_, egl_context_, display_context_attributes); |
|||
|
|||
if (egl_resource_context_ == EGL_NO_CONTEXT) { |
|||
FML_CHECK(false) << "EGL: Failed to create EGL resource context"; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
void UnitySurfaceManager::CleanUp() { |
|||
EGLBoolean result = EGL_FALSE; |
|||
|
|||
if (egl_display_ != EGL_NO_DISPLAY && egl_context_ != EGL_NO_CONTEXT) { |
|||
result = eglDestroyContext(egl_display_, egl_context_); |
|||
egl_context_ = EGL_NO_CONTEXT; |
|||
|
|||
if (result == EGL_FALSE) { |
|||
FML_LOG(ERROR) << "EGL: Failed to destroy context"; |
|||
} |
|||
} |
|||
|
|||
d3d11_device_ = nullptr; |
|||
|
|||
if (egl_display_ != EGL_NO_DISPLAY && |
|||
egl_resource_context_ != EGL_NO_CONTEXT) { |
|||
result = eglDestroyContext(egl_display_, egl_resource_context_); |
|||
egl_resource_context_ = EGL_NO_CONTEXT; |
|||
|
|||
if (result == EGL_FALSE) { |
|||
FML_LOG(ERROR) << "EGL : Failed to destroy resource context"; |
|||
} |
|||
} |
|||
|
|||
if (egl_display_ != EGL_NO_DISPLAY) { |
|||
result = eglTerminate(egl_display_); |
|||
egl_display_ = EGL_NO_DISPLAY; |
|||
|
|||
if (result == EGL_FALSE) { |
|||
FML_LOG(ERROR) << "EGL : Failed to terminate EGL"; |
|||
} |
|||
} |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
// OpenGL ES and EGL includes |
|||
#include <EGL/egl.h> |
|||
#include <EGL/eglext.h> |
|||
#include <EGL/eglplatform.h> |
|||
#include <GLES2/gl2.h> |
|||
#include <GLES2/gl2ext.h> |
|||
// #include <d3d11.h> |
|||
// #include <windows.h> |
|||
|
|||
#include <cstdint> |
|||
|
|||
#include "Unity/IUnityInterface.h" |
|||
#include "flutter/fml/macros.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class UnitySurfaceManager { |
|||
public: |
|||
UnitySurfaceManager(IUnityInterfaces* unity_interfaces); |
|||
~UnitySurfaceManager(); |
|||
|
|||
GLuint CreateRenderSurface(void* native_texture_ptr); |
|||
void DestroyRenderSurface(); |
|||
|
|||
bool ClearCurrent(); |
|||
|
|||
bool MakeCurrent(const EGLSurface surface); |
|||
|
|||
bool MakeResourceCurrent(); |
|||
|
|||
EGLDisplay GetEGLDisplay() const { return egl_display_; } |
|||
|
|||
ID3D11Device* GetD3D11Device() const { return d3d11_device_; } |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(UnitySurfaceManager); |
|||
|
|||
private: |
|||
bool Initialize(IUnityInterfaces* unity_interfaces); |
|||
void CleanUp(); |
|||
|
|||
EGLDisplay egl_display_; |
|||
EGLContext egl_context_; |
|||
EGLContext egl_resource_context_; |
|||
EGLConfig egl_config_; |
|||
bool initialize_succeeded_; |
|||
ID3D11Device* d3d11_device_; |
|||
|
|||
EGLImage fbo_egl_image_ = nullptr; |
|||
GLuint fbo_texture_ = 0; |
|||
GLuint fbo_ = 0; |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
撰写
预览
正在加载...
取消
保存
Reference in new issue