blob: b451c5aa133f87ee96ad8cd1fc0ce5897b657b7d [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 <magenta/device/vfs.h>
#include <mxio/watcher.h>
#include <unistd.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 kDisplayDriverClass[] = "/dev/class/display";
static mx_status_t DriverWatcher(int dirfd,
int event,
const char* fn,
void* cookie) {
if (event == WATCH_EVENT_ADD_FILE && !strcmp(fn, "000")) {
return MX_ERR_STOP;
}
return MX_OK;
}
bool WaitForFirstDisplayDriver() {
fxl::UniqueFD fd(open(kDisplayDriverClass, O_DIRECTORY | O_RDONLY));
if (fd.get() < 0) {
FXL_DLOG(ERROR) << "Failed to open " << kDisplayDriverClass;
return false;
}
mx_status_t status = mxio_watch_directory(
fd.get(), DriverWatcher, mx_deadline_after(MX_SEC(1)), nullptr);
return status == MX_ERR_STOP;
}
VulkanRasterizer::VulkanRasterizer() : compositor_context_(nullptr) {
valid_ = WaitForFirstDisplayDriver();
}
VulkanRasterizer::~VulkanRasterizer() = default;
bool VulkanRasterizer::IsValid() const {
return valid_;
}
void VulkanRasterizer::SetScene(
fidl::InterfaceHandle<scenic::SceneManager> scene_manager,
mx::eventpair import_token,
fxl::Closure metrics_changed_callback) {
ASSERT_IS_GPU_THREAD;
FXL_DCHECK(valid_ && !session_connection_);
session_connection_ = std::make_unique<SessionConnection>(
scenic::SceneManagerPtr::Create(std::move(scene_manager)),
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);
}
{
// 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