blob: 4394b8712d09db1c5bbbcca1071f0bb7a8e657f4 [file] [log] [blame]
// Copyright 2017 The Chromium 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 "flutter/content_handler/vulkan_rasterizer.h"
#include <fcntl.h>
#include <fdio/watcher.h>
#include <unistd.h>
#include <zircon/device/vfs.h>
#include <chrono>
#include <thread>
#include <utility>
#include "flutter/common/threads.h"
#include "flutter/glue/trace_event.h"
#include "lib/fxl/files/unique_fd.h"
namespace flutter_runner {
constexpr char kGpuDriverClass[] = "/dev/class/gpu";
static zx_status_t DriverWatcher(int dirfd,
int event,
const char* fn,
void* cookie) {
if (event == WATCH_EVENT_ADD_FILE && !strcmp(fn, "000")) {
return ZX_ERR_STOP;
}
return ZX_OK;
}
bool WaitForFirstGpuDriver() {
fxl::UniqueFD fd(open(kGpuDriverClass, O_DIRECTORY | O_RDONLY));
if (fd.get() < 0) {
FXL_DLOG(ERROR) << "Failed to open " << kGpuDriverClass;
return false;
}
zx_status_t status = fdio_watch_directory(
fd.get(), DriverWatcher, zx_deadline_after(ZX_SEC(5)), nullptr);
return status == ZX_ERR_STOP;
}
VulkanRasterizer::VulkanRasterizer() : compositor_context_(nullptr) {
valid_ = WaitForFirstGpuDriver();
}
VulkanRasterizer::~VulkanRasterizer() = default;
bool VulkanRasterizer::IsValid() const {
return valid_;
}
void VulkanRasterizer::SetScene(f1dl::InterfaceHandle<ui::Scenic> scenic,
zx::eventpair import_token,
fxl::Closure metrics_changed_callback) {
ASSERT_IS_GPU_THREAD;
FXL_DCHECK(valid_ && !session_connection_);
session_connection_ = std::make_unique<SessionConnection>(
scenic.Bind(), std::move(import_token));
session_connection_->set_metrics_changed_callback(
std::move(metrics_changed_callback));
}
void VulkanRasterizer::Draw(std::unique_ptr<flow::LayerTree> layer_tree,
fxl::Closure callback) {
ASSERT_IS_GPU_THREAD;
FXL_DCHECK(callback != nullptr);
if (layer_tree == nullptr) {
FXL_LOG(ERROR) << "Layer tree was not valid.";
callback();
return;
}
if (!session_connection_) {
FXL_LOG(ERROR) << "Session was not valid.";
callback();
return;
}
if (!session_connection_->has_metrics()) {
// Still awaiting metrics. Will redraw when we get them.
callback();
return;
}
compositor_context_.engine_time().SetLapTime(layer_tree->construction_time());
flow::CompositorContext::ScopedFrame frame = compositor_context_.AcquireFrame(
nullptr, nullptr, true /* instrumentation enabled */);
{
// Preroll the Flutter layer tree. This allows Flutter to perform pre-paint
// optimizations.
TRACE_EVENT0("flutter", "Preroll");
layer_tree->Preroll(frame, session_connection_->metrics().get());
}
{
// Traverse the Flutter layer tree so that the necessary session ops to
// represent the frame are enqueued in the underlying session.
TRACE_EVENT0("flutter", "UpdateScene");
layer_tree->UpdateScene(session_connection_->scene_update_context(),
session_connection_->root_node());
}
{
// Flush all pending session ops.
TRACE_EVENT0("flutter", "SessionPresent");
session_connection_->Present(
frame, [callback = std::move(callback)]() { callback(); });
}
}
} // namespace flutter_runner