blob: c39e344cb5c6fe63c87a0d5bc21746a082393ef1 [file] [log] [blame]
// Copyright 2018 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/lib/ui/scenic/session.h"
#include <lib/async/cpp/task.h>
#include <lib/async/default.h>
namespace scenic_impl {
Session::Session(
SessionId id,
::fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener)
: id_(id), listener_(listener.Bind()), weak_factory_(this) {}
Session::~Session() = default;
void Session::Enqueue(::std::vector<fuchsia::ui::scenic::Command> cmds) {
for (auto& cmd : cmds) {
// TODO(SCN-710): This dispatch is far from optimal in terms of performance.
// We need to benchmark it to figure out whether it matters.
System::TypeId type_id = SystemTypeForCmd(cmd);
auto dispatcher = type_id != System::TypeId::kInvalid
? dispatchers_[type_id].get()
: nullptr;
if (dispatcher) {
dispatcher->DispatchCommand(std::move(cmd));
} else {
EnqueueEvent(std::move(cmd));
}
}
}
void Session::Present(uint64_t presentation_time,
::std::vector<zx::event> acquire_fences,
::std::vector<zx::event> release_fences,
PresentCallback callback) {
// TODO(MZ-469): Move Present logic into Session.
auto& dispatcher = dispatchers_[System::TypeId::kGfx];
FXL_DCHECK(dispatcher);
TempSessionDelegate* delegate =
static_cast<TempSessionDelegate*>(dispatcher.get());
delegate->Present(presentation_time, std::move(acquire_fences),
std::move(release_fences), std::move(callback));
}
void Session::SetCommandDispatchers(
std::array<std::unique_ptr<CommandDispatcher>, System::TypeId::kMaxSystems>
dispatchers) {
for (size_t i = 0; i < System::TypeId::kMaxSystems; ++i) {
dispatchers_[i] = std::move(dispatchers[i]);
}
}
void Session::HitTest(uint32_t node_id, ::fuchsia::ui::gfx::vec3 ray_origin,
::fuchsia::ui::gfx::vec3 ray_direction,
HitTestCallback callback) {
auto& dispatcher = dispatchers_[System::TypeId::kGfx];
FXL_DCHECK(dispatcher);
TempSessionDelegate* delegate =
static_cast<TempSessionDelegate*>(dispatcher.get());
delegate->HitTest(node_id, std::move(ray_origin), std::move(ray_direction),
std::move(callback));
}
void Session::SetDebugName(std::string debug_name) {
auto& dispatcher = dispatchers_[System::TypeId::kGfx];
FXL_DCHECK(dispatcher);
TempSessionDelegate* delegate =
static_cast<TempSessionDelegate*>(dispatcher.get());
delegate->SetDebugName(debug_name);
}
void Session::HitTestDeviceRay(::fuchsia::ui::gfx::vec3 ray_origin,
::fuchsia::ui::gfx::vec3 ray_direction,
HitTestCallback callback) {
auto& dispatcher = dispatchers_[System::TypeId::kGfx];
FXL_DCHECK(dispatcher);
TempSessionDelegate* delegate =
reinterpret_cast<TempSessionDelegate*>(dispatcher.get());
delegate->HitTestDeviceRay(std::move(ray_origin), std::move(ray_direction),
std::move(callback));
}
void Session::PostFlushTask() {
// If this is the first EnqueueEvent() since the last FlushEvent(), post a
// task to ensure that FlushEvents() is called.
if (buffered_events_.empty()) {
async::PostTask(async_get_default_dispatcher(),
[weak = weak_factory_.GetWeakPtr()] {
if (weak) {
weak->FlushEvents();
}
});
}
}
void Session::EnqueueEvent(fuchsia::ui::gfx::Event event) {
PostFlushTask();
fuchsia::ui::scenic::Event scenic_event;
scenic_event.set_gfx(std::move(event));
buffered_events_.push_back(std::move(scenic_event));
}
void Session::EnqueueEvent(fuchsia::ui::scenic::Command unhandled_command) {
PostFlushTask();
fuchsia::ui::scenic::Event scenic_event;
scenic_event.set_unhandled(std::move(unhandled_command));
buffered_events_.push_back(std::move(scenic_event));
}
void Session::EnqueueEvent(fuchsia::ui::input::InputEvent event) {
// Force an immediate flush, preserving event order.
fuchsia::ui::scenic::Event scenic_event;
scenic_event.set_input(std::move(event));
buffered_events_.push_back(std::move(scenic_event));
FlushEvents();
}
void Session::FlushEvents() {
if (!buffered_events_.empty()) {
if (listener_) {
listener_->OnScenicEvent(std::move(buffered_events_));
} else if (event_callback_) {
// Only use the callback if there is no listener. It is difficult to do
// better because we std::move the argument into OnEvent().
for (auto& evt : buffered_events_) {
event_callback_(std::move(evt));
}
}
buffered_events_.clear();
}
}
void Session::ReportError(fxl::LogSeverity severity, std::string error_string) {
switch (severity) {
case fxl::LOG_INFO:
FXL_LOG(INFO) << error_string;
return;
case fxl::LOG_WARNING:
FXL_LOG(WARNING) << error_string;
return;
case fxl::LOG_ERROR:
FXL_LOG(ERROR) << error_string;
if (listener_) {
listener_->OnScenicError(std::move(error_string));
} else if (error_callback_) {
// Only use the callback if there is no listener. It is difficult to do
// better because we std::move the argument into OnEvent().
error_callback_(std::move(error_string));
}
return;
case fxl::LOG_FATAL:
FXL_LOG(FATAL) << error_string;
return;
default:
// Invalid severity.
FXL_DCHECK(false);
}
}
} // namespace scenic_impl