From 59c87e71c956c92a9eca4adeb3aa93f7957d0093 Mon Sep 17 00:00:00 2001 From: xiaowei guan Date: Sun, 31 Jan 2021 03:40:58 +0800 Subject: [PATCH 1/5] Implement message queue to handle vblank request The previous implementation with ecore_thread_run caused would cause a new thread to be recreated every time. The current implementation with ecore_thread_feedback_run and eina_thread_queue,only create one thread. --- shell/platform/tizen/BUILD.gn | 1 + shell/platform/tizen/tizen_vsync_waiter.cc | 96 ++++++++++++++++++---- shell/platform/tizen/tizen_vsync_waiter.h | 6 +- 3 files changed, 85 insertions(+), 18 deletions(-) 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..7ab5bb1679043 100644 --- a/shell/platform/tizen/tizen_vsync_waiter.cc +++ b/shell/platform/tizen/tizen_vsync_waiter.cc @@ -4,40 +4,103 @@ #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_VBLNAK = 0; + +typedef struct { + Eina_Thread_Queue_Msg head; + int value; +} Msg; + +static Eina_Thread_Queue* vblankThreadQueue{nullptr}; TizenVsyncWaiter::TizenVsyncWaiter(TizenEmbedderEngine* engine) : engine_(engine) { if (!CreateTDMVblank()) { FT_LOGE("Failed to create TDM vblank"); DestoryTDMVblank(); + } else { + vblankThreadQueue = eina_thread_queue_new(); + vblankThread_ = + ecore_thread_feedback_run(RequestVblankLoop, NULL, VblankLoopFinish, + VblankLoopFinish, this, EINA_TRUE); } } -TizenVsyncWaiter::~TizenVsyncWaiter() { DestoryTDMVblank(); } +TizenVsyncWaiter::~TizenVsyncWaiter() { + SendMessage(QUEUE_QUIT); + if (vblankThread_) { + ecore_thread_cancel(vblankThread_); + vblankThread_ = nullptr; + } + DestoryTDMVblank(); +} void TizenVsyncWaiter::AsyncWaitForVsync(intptr_t baton) { baton_ = baton; if (TDMValid()) { - ecore_thread_run(RequestVblank, NULL, NULL, this); + SendMessage(QUEUE_REQUEST_VBLNAK); + } +} + +void TizenVsyncWaiter::SendMessage(int val) { + if (!vblankThreadQueue || !vblankThread_) { + FT_LOGE("vblank thread or vblank thread queue not valid"); + return; + } + Msg* msg; + void* ref; + msg = (Msg*)eina_thread_queue_send(vblankThreadQueue, sizeof(Msg), &ref); + msg->value = val; + eina_thread_queue_send_done(vblankThreadQueue, 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 (!vblankThreadQueue) { + FT_LOGE("Vblank thread queue is not valid"); + return; + } + msg = (Msg*)eina_thread_queue_wait(vblankThreadQueue, &ref); + if (msg) { + eina_thread_queue_wait_done(vblankThreadQueue, ref); + } else { + FT_LOGE("Message is null"); + continue; + } + if (msg->value == -1) { + 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); + tizen_vsync_waiter->DestoryTDMVblank(); + return; + } + tdm_client_handle_events(tizen_vsync_waiter->client_); } } +void TizenVsyncWaiter::VblankLoopFinish(void* data, Ecore_Thread* thread) { + FT_LOGD("VblankLoopFinish!!!!!!"); + eina_thread_queue_free(vblankThreadQueue); +} + bool TizenVsyncWaiter::CreateTDMVblank() { tdm_error ret; client_ = tdm_client_create(&ret); @@ -67,6 +130,7 @@ void TizenVsyncWaiter::DestoryTDMVblank() { tdm_client_vblank_destroy(vblank_); vblank_ = nullptr; } + output_ = nullptr; if (client_) { tdm_client_destroy(client_); client_ = nullptr; @@ -80,11 +144,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..fdeb8966b1cb5 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* vblankThread_{nullptr}; }; #endif // EMBEDDER_TIZEN_VSYNC_WAITER_H_ From a509ff28dabeb049e6e6be9fb6e99d03ff8227fa Mon Sep 17 00:00:00 2001 From: xiaowei guan Date: Sun, 31 Jan 2021 03:56:38 +0800 Subject: [PATCH 2/5] Replace -1 with QUEUE_QUIT We have defined QUEUE_QUIT = -1, use QUEUE_QUIT, make the code more readable. --- shell/platform/tizen/tizen_vsync_waiter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/tizen/tizen_vsync_waiter.cc b/shell/platform/tizen/tizen_vsync_waiter.cc index 7ab5bb1679043..003fc3d6e670e 100644 --- a/shell/platform/tizen/tizen_vsync_waiter.cc +++ b/shell/platform/tizen/tizen_vsync_waiter.cc @@ -77,7 +77,7 @@ void TizenVsyncWaiter::RequestVblankLoop(void* data, Ecore_Thread* thread) { FT_LOGE("Message is null"); continue; } - if (msg->value == -1) { + if (msg->value == QUEUE_QUIT) { FT_LOGD("Message queue quit"); return; } From a745ec76f53ebcba2e4dad275c39afd0690db967 Mon Sep 17 00:00:00 2001 From: xiaowei guan Date: Mon, 1 Feb 2021 22:14:40 +0800 Subject: [PATCH 3/5] Check vblank thread queue whether valid before release it. --- shell/platform/tizen/tizen_vsync_waiter.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shell/platform/tizen/tizen_vsync_waiter.cc b/shell/platform/tizen/tizen_vsync_waiter.cc index 003fc3d6e670e..2fa8fb359b6ca 100644 --- a/shell/platform/tizen/tizen_vsync_waiter.cc +++ b/shell/platform/tizen/tizen_vsync_waiter.cc @@ -98,7 +98,10 @@ void TizenVsyncWaiter::RequestVblankLoop(void* data, Ecore_Thread* thread) { void TizenVsyncWaiter::VblankLoopFinish(void* data, Ecore_Thread* thread) { FT_LOGD("VblankLoopFinish!!!!!!"); - eina_thread_queue_free(vblankThreadQueue); + if (vblankThreadQueue) { + eina_thread_queue_free(vblankThreadQueue); + vblankThreadQueue = nullptr; + } } bool TizenVsyncWaiter::CreateTDMVblank() { From 599c9808087335f14b96b2b0d5faeee6f25eb82b Mon Sep 17 00:00:00 2001 From: xiaowei guan Date: Mon, 1 Feb 2021 23:38:52 +0800 Subject: [PATCH 4/5] Rename vblank thread and vblank thread queue --- shell/platform/tizen/tizen_vsync_waiter.cc | 42 +++++++++++----------- shell/platform/tizen/tizen_vsync_waiter.h | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/shell/platform/tizen/tizen_vsync_waiter.cc b/shell/platform/tizen/tizen_vsync_waiter.cc index 2fa8fb359b6ca..749bd15e8e1b7 100644 --- a/shell/platform/tizen/tizen_vsync_waiter.cc +++ b/shell/platform/tizen/tizen_vsync_waiter.cc @@ -10,14 +10,14 @@ #include "flutter/shell/platform/tizen/tizen_log.h" static const int QUEUE_QUIT = -1; -static const int QUEUE_REQUEST_VBLNAK = 0; +static const int QUEUE_REQUEST_VBLANK = 0; typedef struct { Eina_Thread_Queue_Msg head; int value; } Msg; -static Eina_Thread_Queue* vblankThreadQueue{nullptr}; +static Eina_Thread_Queue* vblank_thread_queue{nullptr}; TizenVsyncWaiter::TizenVsyncWaiter(TizenEmbedderEngine* engine) : engine_(engine) { @@ -25,8 +25,8 @@ TizenVsyncWaiter::TizenVsyncWaiter(TizenEmbedderEngine* engine) FT_LOGE("Failed to create TDM vblank"); DestoryTDMVblank(); } else { - vblankThreadQueue = eina_thread_queue_new(); - vblankThread_ = + vblank_thread_queue = eina_thread_queue_new(); + vblank_thread_ = ecore_thread_feedback_run(RequestVblankLoop, NULL, VblankLoopFinish, VblankLoopFinish, this, EINA_TRUE); } @@ -34,9 +34,9 @@ TizenVsyncWaiter::TizenVsyncWaiter(TizenEmbedderEngine* engine) TizenVsyncWaiter::~TizenVsyncWaiter() { SendMessage(QUEUE_QUIT); - if (vblankThread_) { - ecore_thread_cancel(vblankThread_); - vblankThread_ = nullptr; + if (vblank_thread_) { + ecore_thread_cancel(vblank_thread_); + vblank_thread_ = nullptr; } DestoryTDMVblank(); } @@ -44,20 +44,20 @@ TizenVsyncWaiter::~TizenVsyncWaiter() { void TizenVsyncWaiter::AsyncWaitForVsync(intptr_t baton) { baton_ = baton; if (TDMValid()) { - SendMessage(QUEUE_REQUEST_VBLNAK); + SendMessage(QUEUE_REQUEST_VBLANK); } } void TizenVsyncWaiter::SendMessage(int val) { - if (!vblankThreadQueue || !vblankThread_) { + 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(vblankThreadQueue, sizeof(Msg), &ref); + msg = (Msg*)eina_thread_queue_send(vblank_thread_queue, sizeof(Msg), &ref); msg->value = val; - eina_thread_queue_send_done(vblankThreadQueue, ref); + eina_thread_queue_send_done(vblank_thread_queue, ref); } void TizenVsyncWaiter::RequestVblankLoop(void* data, Ecore_Thread* thread) { @@ -66,13 +66,13 @@ void TizenVsyncWaiter::RequestVblankLoop(void* data, Ecore_Thread* thread) { void* ref; Msg* msg; while (!ecore_thread_check(thread)) { - if (!vblankThreadQueue) { + if (!vblank_thread_queue) { FT_LOGE("Vblank thread queue is not valid"); return; } - msg = (Msg*)eina_thread_queue_wait(vblankThreadQueue, &ref); + msg = (Msg*)eina_thread_queue_wait(vblank_thread_queue, &ref); if (msg) { - eina_thread_queue_wait_done(vblankThreadQueue, ref); + eina_thread_queue_wait_done(vblank_thread_queue, ref); } else { FT_LOGE("Message is null"); continue; @@ -82,25 +82,25 @@ void TizenVsyncWaiter::RequestVblankLoop(void* data, Ecore_Thread* thread) { return; } if (!tizen_vsync_waiter->TDMValid()) { - FT_LOGE("TDM not Valid"); + 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); - tizen_vsync_waiter->DestoryTDMVblank(); - return; + tizen_vsync_waiter->SendMessage(QUEUE_REQUEST_VBLANK); + continue; } tdm_client_handle_events(tizen_vsync_waiter->client_); } } void TizenVsyncWaiter::VblankLoopFinish(void* data, Ecore_Thread* thread) { - FT_LOGD("VblankLoopFinish!!!!!!"); - if (vblankThreadQueue) { - eina_thread_queue_free(vblankThreadQueue); - vblankThreadQueue = nullptr; + FT_LOGD("VblankLoopFinish."); + if (vblank_thread_queue) { + eina_thread_queue_free(vblank_thread_queue); + vblank_thread_queue = nullptr; } } diff --git a/shell/platform/tizen/tizen_vsync_waiter.h b/shell/platform/tizen/tizen_vsync_waiter.h index fdeb8966b1cb5..eb4826d4e7feb 100644 --- a/shell/platform/tizen/tizen_vsync_waiter.h +++ b/shell/platform/tizen/tizen_vsync_waiter.h @@ -34,7 +34,7 @@ class TizenVsyncWaiter { tdm_client_vblank* vblank_{nullptr}; TizenEmbedderEngine* engine_{nullptr}; intptr_t baton_{0}; - Ecore_Thread* vblankThread_{nullptr}; + Ecore_Thread* vblank_thread_{nullptr}; }; #endif // EMBEDDER_TIZEN_VSYNC_WAITER_H_ From c7edd5f98359ae97162a7209ffca987e344268be Mon Sep 17 00:00:00 2001 From: xiaowei guan Date: Tue, 2 Feb 2021 03:12:32 +0800 Subject: [PATCH 5/5] Do nothing when vblank wait Requesting again may cause an infinite loop or queue overflow. Do nothing is a better way. --- shell/platform/tizen/tizen_vsync_waiter.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/shell/platform/tizen/tizen_vsync_waiter.cc b/shell/platform/tizen/tizen_vsync_waiter.cc index 749bd15e8e1b7..bb88d0fe09180 100644 --- a/shell/platform/tizen/tizen_vsync_waiter.cc +++ b/shell/platform/tizen/tizen_vsync_waiter.cc @@ -89,7 +89,6 @@ void TizenVsyncWaiter::RequestVblankLoop(void* data, Ecore_Thread* thread) { TdmClientVblankCallback, data); if (error != TDM_ERROR_NONE) { FT_LOGE("tdm_client_vblank_wait error %d", error); - tizen_vsync_waiter->SendMessage(QUEUE_REQUEST_VBLANK); continue; } tdm_client_handle_events(tizen_vsync_waiter->client_);