blob: d3b027cf68db906b4f3b07441b6a138dfaeb2299 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "impeller/renderer/backend/vulkan/fence_waiter_vk.h"
#include <chrono>
#include "flutter/fml/thread.h"
#include "flutter/fml/trace_event.h"
namespace impeller {
FenceWaiterVK::FenceWaiterVK(vk::Device device) : device_(device) {
waiter_thread_ = std::make_unique<std::thread>([&]() { Main(); });
is_valid_ = true;
}
FenceWaiterVK::~FenceWaiterVK() {
Terminate();
if (waiter_thread_) {
waiter_thread_->join();
}
}
bool FenceWaiterVK::IsValid() const {
return is_valid_;
}
bool FenceWaiterVK::AddFence(vk::UniqueFence fence,
const fml::closure& callback) {
if (!IsValid() || !fence || !callback) {
return false;
}
{
std::scoped_lock lock(wait_set_mutex_);
wait_set_[MakeSharedVK(std::move(fence))] = callback;
}
wait_set_cv_.notify_one();
return true;
}
void FenceWaiterVK::Main() {
fml::Thread::SetCurrentThreadName(
fml::Thread::ThreadConfig{"io.flutter.impeller.fence_waiter"});
using namespace std::literals::chrono_literals;
while (true) {
std::unique_lock lock(wait_set_mutex_);
wait_set_cv_.wait(lock, [&]() { return !wait_set_.empty() || terminate_; });
auto wait_set = TrimAndCreateWaitSetLocked();
lock.unlock();
if (!wait_set.has_value()) {
break;
}
if (wait_set->empty()) {
continue;
}
auto result = device_.waitForFences(
wait_set->size(), // fences count
wait_set->data(), // fences
false, // wait for all
std::chrono::nanoseconds{100ms}.count() // timeout (ns)
);
if (!(result == vk::Result::eSuccess || result == vk::Result::eTimeout)) {
break;
}
}
}
std::optional<std::vector<vk::Fence>>
FenceWaiterVK::TrimAndCreateWaitSetLocked() {
if (terminate_) {
return std::nullopt;
}
TRACE_EVENT0("impeller", "TrimFences");
std::vector<vk::Fence> fences;
fences.reserve(wait_set_.size());
for (auto it = wait_set_.begin(); it != wait_set_.end();) {
switch (device_.getFenceStatus(it->first->Get())) {
case vk::Result::eSuccess: // Signalled.
it->second();
it = wait_set_.erase(it);
break;
case vk::Result::eNotReady: // Un-signalled.
fences.push_back(it->first->Get());
it++;
break;
default:
return std::nullopt;
}
}
return fences;
}
void FenceWaiterVK::Terminate() {
{
std::scoped_lock lock(wait_set_mutex_);
terminate_ = true;
}
wait_set_cv_.notify_one();
}
} // namespace impeller