diff --git a/shell/platform/tizen/BUILD.gn b/shell/platform/tizen/BUILD.gn index 72e5620a04c22..a0007768953d6 100644 --- a/shell/platform/tizen/BUILD.gn +++ b/shell/platform/tizen/BUILD.gn @@ -105,6 +105,7 @@ source_set("flutter_tizen") { "ecore", "ecore_imf", "ecore_input", + "eina", "EGL", "evas", "flutter_engine", diff --git a/shell/platform/tizen/tizen_vsync_waiter.cc b/shell/platform/tizen/tizen_vsync_waiter.cc index d7ef6accb56d0..bb88d0fe09180 100644 --- a/shell/platform/tizen/tizen_vsync_waiter.cc +++ b/shell/platform/tizen/tizen_vsync_waiter.cc @@ -4,37 +4,102 @@ #include "tizen_vsync_waiter.h" +#include + #include "flutter/shell/platform/tizen/tizen_embedder_engine.h" #include "flutter/shell/platform/tizen/tizen_log.h" -void TizenVsyncWaiter::RequestVblank(void* data, Ecore_Thread* thread) { - TizenVsyncWaiter* tizen_vsync_waiter = - reinterpret_cast(data); - if (!ecore_thread_check(thread)) { - tdm_error error = tdm_client_vblank_wait(tizen_vsync_waiter->vblank_, 1, - TdmClientVblankCallback, data); - if (error != TDM_ERROR_NONE) { - FT_LOGE("tdm_client_vblank_wait error %d", error); - return; - } - tdm_client_handle_events(tizen_vsync_waiter->client_); - } -} +static const int QUEUE_QUIT = -1; +static const int QUEUE_REQUEST_VBLANK = 0; + +typedef struct { + Eina_Thread_Queue_Msg head; + int value; +} Msg; + +static Eina_Thread_Queue* vblank_thread_queue{nullptr}; TizenVsyncWaiter::TizenVsyncWaiter(TizenEmbedderEngine* engine) : engine_(engine) { if (!CreateTDMVblank()) { FT_LOGE("Failed to create TDM vblank"); DestoryTDMVblank(); + } else { + vblank_thread_queue = eina_thread_queue_new(); + vblank_thread_ = + ecore_thread_feedback_run(RequestVblankLoop, NULL, VblankLoopFinish, + VblankLoopFinish, this, EINA_TRUE); } } -TizenVsyncWaiter::~TizenVsyncWaiter() { DestoryTDMVblank(); } +TizenVsyncWaiter::~TizenVsyncWaiter() { + SendMessage(QUEUE_QUIT); + if (vblank_thread_) { + ecore_thread_cancel(vblank_thread_); + vblank_thread_ = nullptr; + } + DestoryTDMVblank(); +} void TizenVsyncWaiter::AsyncWaitForVsync(intptr_t baton) { baton_ = baton; if (TDMValid()) { - ecore_thread_run(RequestVblank, NULL, NULL, this); + SendMessage(QUEUE_REQUEST_VBLANK); + } +} + +void TizenVsyncWaiter::SendMessage(int val) { + if (!vblank_thread_queue || !vblank_thread_) { + FT_LOGE("vblank thread or vblank thread queue not valid"); + return; + } + Msg* msg; + void* ref; + msg = (Msg*)eina_thread_queue_send(vblank_thread_queue, sizeof(Msg), &ref); + msg->value = val; + eina_thread_queue_send_done(vblank_thread_queue, ref); +} + +void TizenVsyncWaiter::RequestVblankLoop(void* data, Ecore_Thread* thread) { + TizenVsyncWaiter* tizen_vsync_waiter = + reinterpret_cast(data); + void* ref; + Msg* msg; + while (!ecore_thread_check(thread)) { + if (!vblank_thread_queue) { + FT_LOGE("Vblank thread queue is not valid"); + return; + } + msg = (Msg*)eina_thread_queue_wait(vblank_thread_queue, &ref); + if (msg) { + eina_thread_queue_wait_done(vblank_thread_queue, ref); + } else { + FT_LOGE("Message is null"); + continue; + } + if (msg->value == QUEUE_QUIT) { + FT_LOGD("Message queue quit"); + return; + } + if (!tizen_vsync_waiter->TDMValid()) { + FT_LOGE("TDM not valid"); + return; + } + tdm_error error = tdm_client_vblank_wait(tizen_vsync_waiter->vblank_, 1, + TdmClientVblankCallback, data); + if (error != TDM_ERROR_NONE) { + FT_LOGE("tdm_client_vblank_wait error %d", error); + continue; + } + tdm_client_handle_events(tizen_vsync_waiter->client_); + } +} + +void TizenVsyncWaiter::VblankLoopFinish(void* data, Ecore_Thread* thread) { + FT_LOGD("VblankLoopFinish."); + if (vblank_thread_queue) { + eina_thread_queue_free(vblank_thread_queue); + vblank_thread_queue = nullptr; } } @@ -67,6 +132,7 @@ void TizenVsyncWaiter::DestoryTDMVblank() { tdm_client_vblank_destroy(vblank_); vblank_ = nullptr; } + output_ = nullptr; if (client_) { tdm_client_destroy(client_); client_ = nullptr; @@ -80,11 +146,9 @@ void TizenVsyncWaiter::TdmClientVblankCallback( unsigned int tv_sec, unsigned int tv_usec, void* user_data) { TizenVsyncWaiter* tizen_vsync_waiter = reinterpret_cast(user_data); - FT_ASSERT(tizen_vsync_waiter != nullptr); FT_ASSERT(tizen_vsync_waiter->engine_ != nullptr); FT_ASSERT(tizen_vsync_waiter->engine_->flutter_engine != nullptr); - uint64_t frame_start_time_nanos = tv_sec * 1e9 + tv_usec * 1e3; uint64_t frame_target_time_nanos = 16.6 * 1e6 + frame_start_time_nanos; FlutterEngineOnVsync(tizen_vsync_waiter->engine_->flutter_engine, diff --git a/shell/platform/tizen/tizen_vsync_waiter.h b/shell/platform/tizen/tizen_vsync_waiter.h index 7566e3a2d980b..eb4826d4e7feb 100644 --- a/shell/platform/tizen/tizen_vsync_waiter.h +++ b/shell/platform/tizen/tizen_vsync_waiter.h @@ -7,6 +7,7 @@ #include #include + #include "flutter/shell/platform/embedder/embedder.h" class TizenEmbedderEngine; @@ -21,16 +22,19 @@ class TizenVsyncWaiter { bool CreateTDMVblank(); void DestoryTDMVblank(); bool TDMValid(); + void SendMessage(int val); static void TdmClientVblankCallback(tdm_client_vblank* vblank, tdm_error error, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void* user_data); - static void RequestVblank(void* data, Ecore_Thread* thread); + static void RequestVblankLoop(void* data, Ecore_Thread* thread); + static void VblankLoopFinish(void* data, Ecore_Thread* thread); tdm_client* client_{nullptr}; tdm_client_output* output_{nullptr}; tdm_client_vblank* vblank_{nullptr}; TizenEmbedderEngine* engine_{nullptr}; intptr_t baton_{0}; + Ecore_Thread* vblank_thread_{nullptr}; }; #endif // EMBEDDER_TIZEN_VSYNC_WAITER_H_