Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 14 additions & 90 deletions flutter/shell/platform/tizen/tizen_vsync_waiter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,107 +3,32 @@
// found in the LICENSE file.

#include "tizen_vsync_waiter.h"

#include <eina_thread_queue.h>

#include "flutter/shell/platform/tizen/flutter_tizen_engine.h"
#include "flutter/shell/platform/tizen/logger.h"

namespace flutter {

namespace {

constexpr int kMessageQuit = -1;
constexpr int kMessageRequestVblank = 0;

struct Message {
Eina_Thread_Queue_Msg head;
int event;
intptr_t baton;
};

} // namespace

TizenVsyncWaiter::TizenVsyncWaiter(FlutterTizenEngine* engine) {
tdm_client_ = std::make_shared<TdmClient>(engine);

vblank_thread_ = ecore_thread_feedback_run(RunVblankLoop, nullptr, nullptr,
nullptr, this, EINA_TRUE);
}
TizenVsyncWaiter::TizenVsyncWaiter(FlutterTizenEngine* engine)
: tdm_client_(std::make_shared<TdmClient>(engine)),
message_loop_(std::make_unique<MessageLoop>()) {}

TizenVsyncWaiter::~TizenVsyncWaiter() {
tdm_client_->OnEngineStop();

SendMessage(kMessageQuit, 0);

if (vblank_thread_) {
ecore_thread_cancel(vblank_thread_);
vblank_thread_ = nullptr;
}
}

void TizenVsyncWaiter::AsyncWaitForVsync(intptr_t baton) {
SendMessage(kMessageRequestVblank, baton);
}

void TizenVsyncWaiter::SendMessage(int event, intptr_t baton) {
if (!vblank_thread_ || ecore_thread_check(vblank_thread_)) {
FT_LOG(Error) << "Invalid vblank thread.";
return;
}

if (!vblank_thread_queue_) {
FT_LOG(Error) << "Invalid vblank thread queue.";
return;
}

void* ref;
Message* message = static_cast<Message*>(
eina_thread_queue_send(vblank_thread_queue_, sizeof(Message), &ref));
message->event = event;
message->baton = baton;
eina_thread_queue_send_done(vblank_thread_queue_, ref);
}

void TizenVsyncWaiter::RunVblankLoop(void* data, Ecore_Thread* thread) {
auto* self = static_cast<TizenVsyncWaiter*>(data);

std::weak_ptr<TdmClient> tdm_client = self->tdm_client_;
if (!tdm_client.lock()->IsValid()) {
FT_LOG(Error) << "Invalid tdm_client.";
ecore_thread_cancel(thread);
return;
}

Eina_Thread_Queue* vblank_thread_queue = eina_thread_queue_new();
if (!vblank_thread_queue) {
FT_LOG(Error) << "Invalid vblank thread queue.";
ecore_thread_cancel(thread);
return;
}
self->vblank_thread_queue_ = vblank_thread_queue;

while (!ecore_thread_check(thread)) {
void* ref;
Message* message = static_cast<Message*>(
eina_thread_queue_wait(vblank_thread_queue, &ref));
if (message->event == kMessageQuit) {
eina_thread_queue_wait_done(vblank_thread_queue, ref);
break;
}
intptr_t baton = message->baton;
eina_thread_queue_wait_done(vblank_thread_queue, ref);

if (tdm_client.expired()) {
break;
std::weak_ptr<TdmClient> tdm_client = tdm_client_;
message_loop_->PostTask([tdm_client_weak = std::move(tdm_client), baton]() {
if (auto tdm_client = tdm_client_weak.lock()) {
if (tdm_client->IsValid()) {
tdm_client->AwaitVblank(baton);
} else {
FT_LOG(Error) << "tdm client is invalid, task cancelled";
}
} else {
FT_LOG(Error) << "tdm client is null, task cancelled";
}
tdm_client.lock()->AwaitVblank(baton);
}

if (vblank_thread_queue) {
eina_thread_queue_free(vblank_thread_queue);
self->vblank_thread_queue_ = nullptr;
}
});
}

TdmClient::TdmClient(FlutterTizenEngine* engine) {
Expand All @@ -126,7 +51,6 @@ TdmClient::TdmClient(FlutterTizenEngine* engine) {
return;
}
tdm_client_vblank_set_enable_fake(vblank_, 1);

engine_ = engine;
}

Expand Down
76 changes: 69 additions & 7 deletions flutter/shell/platform/tizen/tizen_vsync_waiter.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
#ifndef EMBEDDER_TIZEN_VSYNC_WAITER_H_
#define EMBEDDER_TIZEN_VSYNC_WAITER_H_

#include <Ecore.h>
#include <tdm_client.h>

#include <atomic>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>

#include "flutter/shell/platform/embedder/embedder.h"

Expand Down Expand Up @@ -48,17 +52,75 @@ class TizenVsyncWaiter {
public:
TizenVsyncWaiter(FlutterTizenEngine* engine);
virtual ~TizenVsyncWaiter();

void AsyncWaitForVsync(intptr_t baton);

private:
void SendMessage(int event, intptr_t baton);

static void RunVblankLoop(void* data, Ecore_Thread* thread);
class MessageLoop {
public:
using Task = std::function<void()>;

MessageLoop() : quit_(false) {
loop_thread_ = std::thread(&MessageLoop::Run, this);
}

~MessageLoop() { Quit(); }

void PostTask(Task task) {
{
std::lock_guard<std::mutex> lock(mutex_);
if (quit_) {
return;
}
tasks_.push(std::move(task));
}
cond_.notify_one();
}

void Quit() {
{
std::lock_guard<std::mutex> lock(mutex_);
if (quit_) {
return;
}
quit_ = true;
}
cond_.notify_all();

if (loop_thread_.joinable()) {
loop_thread_.join();
}
}

private:
void Run() {
while (true) {
Task task;
{
std::unique_lock<std::mutex> lock(mutex_);
cond_.wait(lock, [this] { return !tasks_.empty() || quit_; });
if (quit_) {
break;
}

task = std::move(tasks_.front());
tasks_.pop();
}

if (task) {
task();
}
}
}

std::queue<Task> tasks_;
std::mutex mutex_;
std::condition_variable cond_;
std::atomic<bool> quit_;
std::thread loop_thread_;
};

std::shared_ptr<TdmClient> tdm_client_;
Ecore_Thread* vblank_thread_ = nullptr;
Eina_Thread_Queue* vblank_thread_queue_ = nullptr;
std::unique_ptr<MessageLoop> message_loop_;
};

} // namespace flutter
Expand Down