| // 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 <trace/event.h> |
| |
| #include "garnet/bin/ui/sketchy/frame.h" |
| #include "garnet/bin/ui/sketchy/resources/import_node.h" |
| #include "garnet/bin/ui/sketchy/resources/stroke.h" |
| #include "src/ui/lib/escher/util/fuchsia_utils.h" |
| |
| namespace sketchy_service { |
| |
| CanvasImpl::CanvasImpl(async::Loop* loop, scenic::Session* session, |
| escher::EscherWeakPtr weak_escher) |
| : loop_(loop), |
| session_(session), |
| escher_(weak_escher), |
| buffer_factory_(weak_escher->gpu_allocator(), |
| weak_escher->resource_recycler()), |
| shared_buffer_pool_(session, &buffer_factory_), |
| stroke_manager_(std::move(weak_escher)) {} |
| |
| void CanvasImpl::Init( |
| fidl::InterfaceHandle<::fuchsia::ui::sketchy::CanvasListener> listener) { |
| // TODO(SCN-269): unimplemented. |
| FXL_LOG(ERROR) << "Init: unimplemented."; |
| } |
| |
| void CanvasImpl::Enqueue( |
| std::vector<::fuchsia::ui::sketchy::Command> commands) { |
| // TODO: Use `AddAll()` when fidl::VectorPtr supports it. |
| for (size_t i = 0; i < commands.size(); ++i) { |
| commands_.push_back(std::move(commands.at(i))); |
| } |
| } |
| |
| void CanvasImpl::Present(uint64_t presentation_time, PresentCallback callback) { |
| TRACE_DURATION("gfx", "CanvasImpl::Present"); |
| TRACE_FLOW_END("gfx", "PresentCanvas", canvas_present_count_); |
| ++canvas_present_count_; |
| TRACE_FLOW_BEGIN("gfx", "RequestScenicPresent", |
| request_scenic_present_count_); |
| |
| // TODO(SCN-269): Present() should behave the same way as Scenic. |
| // Specifically, Commands shouldn't be applied immediately. Instead a |
| // frame-request should be triggered and the Commands enqueue; when the |
| // corresponding frame is processed all Commands that are scheduled for the |
| // current frame's presentation time are applied. |
| for (auto it = commands_->begin(); it != commands_->end(); ++it) { |
| if (!ApplyCommand(std::move(*it))) { |
| loop_->Quit(); |
| } |
| } |
| commands_.reset(); |
| callbacks_.push_back(std::move(callback)); |
| RequestScenicPresent(presentation_time); |
| } |
| |
| void CanvasImpl::RequestScenicPresent(uint64_t presentation_time) { |
| TRACE_DURATION("gfx", "CanvasImpl::RequestScenicPresent"); |
| if (is_scenic_present_requested_) { |
| return; |
| } |
| is_scenic_present_requested_ = true; |
| |
| auto session_callback = [this, callbacks = std::move(callbacks_)]( |
| fuchsia::images::PresentationInfo info) { |
| FXL_DCHECK(is_scenic_present_requested_); |
| is_scenic_present_requested_ = false; |
| for (auto& callback : callbacks) { |
| callback(info); |
| } |
| RequestScenicPresent(info.presentation_time + info.presentation_interval); |
| }; |
| callbacks_.clear(); |
| |
| TRACE_FLOW_END("gfx", "RequestScenicPresent", request_scenic_present_count_); |
| ++request_scenic_present_count_; |
| TRACE_FLOW_BEGIN("gfx", "Session::Present", session_present_count_); |
| ++session_present_count_; |
| |
| auto frame = Frame(escher_.get(), &shared_buffer_pool_, &buffer_factory_); |
| if (frame.init_failed()) { |
| session_->Present(presentation_time, std::move(session_callback)); |
| return; |
| } |
| |
| stroke_manager_.Update(&frame); |
| frame.RequestScenicPresent(session_, presentation_time, |
| std::move(session_callback)); |
| } |
| |
| bool CanvasImpl::ApplyCommand(::fuchsia::ui::sketchy::Command command) { |
| switch (command.Which()) { |
| case ::fuchsia::ui::sketchy::Command::Tag::kCreateResource: |
| return ApplyCreateResourceCmd(std::move(command.create_resource())); |
| case ::fuchsia::ui::sketchy::Command::Tag::kReleaseResource: |
| return ApplyReleaseResourceCmd(std::move(command.release_resource())); |
| case ::fuchsia::ui::sketchy::Command::Tag::kSetPath: |
| return ApplySetPathCmd(std::move(command.set_path())); |
| case ::fuchsia::ui::sketchy::Command::Tag::kAddStroke: |
| return ApplyAddStrokeCmd(std::move(command.add_stroke())); |
| case ::fuchsia::ui::sketchy::Command::Tag::kRemoveStroke: |
| return ApplyRemoveStrokeCmd(std::move(command.remove_stroke())); |
| case ::fuchsia::ui::sketchy::Command::Tag::kBeginStroke: |
| return ApplyBeginStrokeCmd(std::move(command.begin_stroke())); |
| case ::fuchsia::ui::sketchy::Command::Tag::kExtendStroke: |
| return ApplyExtendStrokeCmd(std::move(command.extend_stroke())); |
| case ::fuchsia::ui::sketchy::Command::Tag::kFinishStroke: |
| return ApplyFinishStrokeCmd(std::move(command.finish_stroke())); |
| case ::fuchsia::ui::sketchy::Command::Tag::kClearGroup: |
| return ApplyClearGroupCmd(std::move(command.clear_group())); |
| case ::fuchsia::ui::sketchy::Command::Tag::kScenicImportResource: |
| return ApplyScenicImportResourceCmd( |
| std::move(command.scenic_import_resource())); |
| case ::fuchsia::ui::sketchy::Command::Tag::kScenicAddChild: |
| return ApplyScenicAddChildCmd(std::move(command.scenic_add_child())); |
| default: |
| FXL_DCHECK(false) << "Unsupported op: " |
| << static_cast<uint32_t>(command.Which()); |
| return false; |
| } |
| } |
| |
| bool CanvasImpl::ApplyCreateResourceCmd( |
| ::fuchsia::ui::sketchy::CreateResourceCmd create_resource) { |
| switch (create_resource.args.Which()) { |
| case ::fuchsia::ui::sketchy::ResourceArgs::Tag::kStroke: |
| return CreateStroke(create_resource.id, create_resource.args.stroke()); |
| case ::fuchsia::ui::sketchy::ResourceArgs::Tag::kStrokeGroup: |
| return CreateStrokeGroup(create_resource.id, |
| create_resource.args.stroke_group()); |
| default: |
| FXL_DCHECK(false) << "Unsupported resource: " |
| << static_cast<uint32_t>(create_resource.args.Which()); |
| return false; |
| } |
| } |
| |
| bool CanvasImpl::CreateStroke(ResourceId id, |
| ::fuchsia::ui::sketchy::Stroke stroke) { |
| return resource_map_.AddResource( |
| id, fxl::MakeRefCounted<Stroke>(stroke_manager_.stroke_tessellator(), |
| &buffer_factory_)); |
| } |
| |
| bool CanvasImpl::CreateStrokeGroup( |
| ResourceId id, ::fuchsia::ui::sketchy::StrokeGroup stroke_group) { |
| return resource_map_.AddResource(id, |
| fxl::MakeRefCounted<StrokeGroup>(session_)); |
| } |
| |
| bool CanvasImpl::ApplyReleaseResourceCmd( |
| ::fuchsia::ui::sketchy::ReleaseResourceCmd command) { |
| return resource_map_.RemoveResource(command.id); |
| } |
| |
| bool CanvasImpl::ApplySetPathCmd( |
| ::fuchsia::ui::sketchy::SetStrokePathCmd command) { |
| auto stroke = resource_map_.FindResource<Stroke>(command.stroke_id); |
| if (!stroke) { |
| FXL_LOG(ERROR) << "No Stroke of id " << command.stroke_id << " was found!"; |
| return false; |
| } |
| return stroke_manager_.SetStrokePath( |
| stroke, std::make_unique<StrokePath>(std::move(command.path))); |
| } |
| |
| bool CanvasImpl::ApplyAddStrokeCmd( |
| ::fuchsia::ui::sketchy::AddStrokeCmd command) { |
| auto stroke = resource_map_.FindResource<Stroke>(command.stroke_id); |
| if (!stroke) { |
| FXL_LOG(ERROR) << "No Stroke of id " << command.stroke_id << " was found!"; |
| return false; |
| } |
| auto group = resource_map_.FindResource<StrokeGroup>(command.group_id); |
| if (!group) { |
| FXL_LOG(ERROR) << "No StrokeGroup of id " << command.group_id |
| << " was found!"; |
| return false; |
| } |
| return stroke_manager_.AddStrokeToGroup(stroke, group); |
| } |
| |
| bool CanvasImpl::ApplyRemoveStrokeCmd( |
| ::fuchsia::ui::sketchy::RemoveStrokeCmd command) { |
| auto stroke = resource_map_.FindResource<Stroke>(command.stroke_id); |
| if (!stroke) { |
| FXL_LOG(ERROR) << "No Stroke of id " << command.stroke_id << " was found!"; |
| return false; |
| } |
| auto group = resource_map_.FindResource<StrokeGroup>(command.group_id); |
| if (!group) { |
| FXL_LOG(ERROR) << "No StrokeGroup of id " << command.group_id |
| << " was found!"; |
| return false; |
| } |
| return stroke_manager_.RemoveStrokeFromGroup(stroke, group); |
| } |
| |
| bool CanvasImpl::ApplyBeginStrokeCmd( |
| ::fuchsia::ui::sketchy::BeginStrokeCmd command) { |
| auto stroke = resource_map_.FindResource<Stroke>(command.stroke_id); |
| if (!stroke) { |
| FXL_LOG(ERROR) << "No Stroke of id " << command.stroke_id << " was found!"; |
| return false; |
| } |
| const auto& pos = command.touch.position; |
| return stroke_manager_.BeginStroke(stroke, {pos.x, pos.y}); |
| } |
| |
| bool CanvasImpl::ApplyExtendStrokeCmd( |
| ::fuchsia::ui::sketchy::ExtendStrokeCmd command) { |
| auto stroke = resource_map_.FindResource<Stroke>(command.stroke_id); |
| if (!stroke) { |
| FXL_LOG(ERROR) << "No Stroke of id " << command.stroke_id << " was found!"; |
| return false; |
| } |
| std::vector<glm::vec2> pts; |
| pts.reserve(command.touches.size()); |
| for (const auto& touch : command.touches) { |
| pts.push_back({touch.position.x, touch.position.y}); |
| } |
| return stroke_manager_.ExtendStroke(stroke, std::move(pts)); |
| } |
| |
| bool CanvasImpl::ApplyFinishStrokeCmd( |
| ::fuchsia::ui::sketchy::FinishStrokeCmd command) { |
| auto stroke = resource_map_.FindResource<Stroke>(command.stroke_id); |
| if (!stroke) { |
| FXL_LOG(ERROR) << "No Stroke of id " << command.stroke_id << " was found!"; |
| return false; |
| } |
| return stroke_manager_.FinishStroke(stroke); |
| } |
| |
| bool CanvasImpl::ApplyClearGroupCmd( |
| ::fuchsia::ui::sketchy::ClearGroupCmd command) { |
| auto group = resource_map_.FindResource<StrokeGroup>(command.group_id); |
| if (!group) { |
| FXL_LOG(ERROR) << "No Group of id " << command.group_id << " was found!"; |
| return false; |
| } |
| return stroke_manager_.ClearGroup(group); |
| } |
| |
| bool CanvasImpl::ApplyScenicImportResourceCmd( |
| fuchsia::ui::gfx::ImportResourceCmd import_resource) { |
| switch (import_resource.spec) { |
| case fuchsia::ui::gfx::ImportSpec::NODE: |
| return ScenicImportNode(import_resource.id, |
| std::move(import_resource.token)); |
| } |
| } |
| |
| bool CanvasImpl::ScenicImportNode(ResourceId id, zx::eventpair token) { |
| // 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::ApplyScenicAddChildCmd( |
| fuchsia::ui::gfx::AddChildCmd 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 stroke_manager_.AddNewGroup(stroke_group); |
| } |
| |
| } // namespace sketchy_service |