blob: 41b3d020d43196eb330bb50383ca0892107a2178 [file] [log] [blame]
// Copyright 2017 The Fuchsia 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 "garnet/bin/ui/sketchy/canvas.h"
#include "garnet/bin/ui/sketchy/resources/import_node.h"
#include "garnet/bin/ui/sketchy/resources/stroke.h"
#include "lib/escher/impl/command_buffer_pool.h"
#include "lib/escher/util/fuchsia_utils.h"
#include "lib/fsl/tasks/message_loop.h"
namespace sketchy_service {
CanvasImpl::CanvasImpl(scenic_lib::Session* session, escher::Escher* escher)
: session_(session),
escher_(escher),
buffer_factory_(escher),
stroke_manager_(escher) {}
void CanvasImpl::Init(fidl::InterfaceHandle<sketchy::CanvasListener> listener) {
// TODO(MZ-269): unimplemented.
FXL_LOG(ERROR) << "Init: unimplemented.";
}
void CanvasImpl::Enqueue(fidl::Array<sketchy::OpPtr> ops) {
// TODO: Use `AddAll()` when fidl::Array supports it.
for (auto& op : ops) {
ops_.push_back(std::move(op));
}
}
void CanvasImpl::Present(uint64_t presentation_time,
const PresentCallback& callback) {
// TODO(MZ-269): Present() should behave the same way as Scenic. Specifically,
// Ops shouldn't be applied immediately. Instead a frame-request should be
// triggered and the Ops enqueue; when the corresponding frame is processed
// all Ops that are scheduled for the current frame's presentation time are
// applied.
for (auto& op : ops_) {
if (!ApplyOp(op)) {
fsl::MessageLoop::GetCurrent()->QuitNow();
}
}
ops_.reset();
auto command = escher_->command_buffer_pool()->GetCommandBuffer();
stroke_manager_.Update(command, &buffer_factory_);
auto pair = escher::NewSemaphoreEventPair(escher_);
command->AddSignalSemaphore(std::move(pair.first));
session_->EnqueueAcquireFence(std::move(pair.second));
command->Submit(escher_->device()->vk_main_queue(), {});
callbacks_.push_back(std::move(callback));
RequestScenicPresent(presentation_time);
}
void CanvasImpl::RequestScenicPresent(uint64_t presentation_time) {
if (is_scenic_present_requested_) {
return;
}
is_scenic_present_requested_ = true;
auto session_callback = [this, callbacks = std::move(callbacks_)](
scenic::PresentationInfoPtr info) {
FXL_DCHECK(is_scenic_present_requested_);
is_scenic_present_requested_ = false;
for (auto& callback : callbacks) {
auto _info = scenic::PresentationInfo::New();
_info->presentation_time = _info->presentation_time;
_info->presentation_interval = _info->presentation_interval;
callback(std::move(_info));
}
RequestScenicPresent(info->presentation_time + info->presentation_interval);
};
callbacks_.clear();
session_->Present(presentation_time, std::move(session_callback));
}
bool CanvasImpl::ApplyOp(const sketchy::OpPtr& op) {
switch (op->which()) {
case sketchy::Op::Tag::CREATE_RESOURCE:
return ApplyCreateResourceOp(op->get_create_resource());
case sketchy::Op::Tag::RELEASE_RESOURCE:
return ApplyReleaseResourceOp(op->get_release_resource());
case sketchy::Op::Tag::SET_PATH:
return ApplySetPathOp(op->get_set_path());
case sketchy::Op::Tag::ADD_STROKE:
return ApplyAddStrokeOp(op->get_add_stroke());
case sketchy::Op::Tag::REMOVE_STROKE:
return ApplyRemoveStrokeOp(op->get_remove_stroke());
case sketchy::Op::Tag::SCENIC_IMPORT_RESOURCE:
return ApplyScenicImportResourceOp(op->get_scenic_import_resource());
case sketchy::Op::Tag::SCENIC_ADD_CHILD:
return ApplyScenicAddChildOp(op->get_scenic_add_child());
default:
FXL_DCHECK(false) << "Unsupported op: "
<< static_cast<uint32_t>(op->which());
return false;
}
}
bool CanvasImpl::ApplyCreateResourceOp(
const sketchy::CreateResourceOpPtr& create_resource) {
switch (create_resource->args->which()) {
case sketchy::ResourceArgs::Tag::STROKE:
return CreateStroke(create_resource->id,
create_resource->args->get_stroke());
case sketchy::ResourceArgs::Tag::STROKE_GROUP:
return CreateStrokeGroup(create_resource->id,
create_resource->args->get_stroke_group());
default:
FXL_DCHECK(false) << "Unsupported resource: "
<< static_cast<uint32_t>(
create_resource->args->which());
return false;
}
}
bool CanvasImpl::CreateStroke(ResourceId id, const sketchy::StrokePtr& stroke) {
return resource_map_.AddResource(
id,
fxl::MakeRefCounted<Stroke>(escher_,
stroke_manager_.stroke_tessellator()));
}
bool CanvasImpl::CreateStrokeGroup(
ResourceId id,
const sketchy::StrokeGroupPtr& stroke_group) {
return resource_map_.AddResource(
id, fxl::MakeRefCounted<StrokeGroup>(session_, &buffer_factory_));
}
bool CanvasImpl::ApplyReleaseResourceOp(
const sketchy::ReleaseResourceOpPtr& op) {
return resource_map_.RemoveResource(op->id);
}
bool CanvasImpl::ApplySetPathOp(const sketchy::SetStrokePathOpPtr& op) {
auto stroke = resource_map_.FindResource<Stroke>(op->stroke_id);
if (!stroke) {
FXL_LOG(ERROR) << "No Stroke of id " << op->stroke_id << " was found!";
return false;
}
return stroke_manager_.SetStrokePath(
stroke, std::make_unique<StrokePath>(std::move(op->path)));
}
bool CanvasImpl::ApplyAddStrokeOp(const sketchy::AddStrokeOpPtr& op) {
auto stroke = resource_map_.FindResource<Stroke>(op->stroke_id);
if (!stroke) {
FXL_LOG(ERROR) << "No Stroke of id " << op->stroke_id << " was found!";
return false;
}
auto group = resource_map_.FindResource<StrokeGroup>(op->group_id);
if (!group) {
FXL_LOG(ERROR) << "No StrokeGroup of id " << op->group_id << " was found!";
return false;
}
return stroke_manager_.AddStrokeToGroup(stroke, group);
}
bool CanvasImpl::ApplyRemoveStrokeOp(const sketchy::RemoveStrokeOpPtr& op) {
// TODO(MZ-269): unimplemented.
FXL_LOG(ERROR) << "ApplyRemoveStrokeOp: unimplemented.";
return false;
}
bool CanvasImpl::ApplyScenicImportResourceOp(
const scenic::ImportResourceOpPtr& import_resource) {
switch (import_resource->spec) {
case scenic::ImportSpec::NODE:
return ScenicImportNode(import_resource->id,
std::move(import_resource->token));
}
}
bool CanvasImpl::ScenicImportNode(ResourceId id, zx::eventpair token) {
FXL_LOG(INFO) << "CanvasImpl::ScenicImportNode()";
// As a client of Scenic, Canvas creates an ImportNode given token.
auto node = fxl::MakeRefCounted<ImportNode>(session_, std::move(token));
resource_map_.AddResource(id, std::move(node));
return true;
}
bool CanvasImpl::ApplyScenicAddChildOp(const scenic::AddChildOpPtr& add_child) {
auto import_node = resource_map_.FindResource<ImportNode>(add_child->node_id);
auto stroke_group =
resource_map_.FindResource<StrokeGroup>(add_child->child_id);
if (!import_node || !stroke_group) {
return false;
}
import_node->AddChild(stroke_group);
return true;
}
} // namespace sketchy_service