// 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 "lib/ui/scenic/cpp/session.h" #include <stdio.h> #include <zircon/assert.h> #include "lib/ui/scenic/cpp/commands.h" namespace scenic { constexpr size_t kCommandsPerMessage = (ZX_CHANNEL_MAX_MSG_BYTES - sizeof(fidl_message_header_t) - sizeof(fidl_vector_t)) / sizeof(fuchsia::ui::scenic::Command); SessionPtrAndListenerRequest CreateScenicSessionPtrAndListenerRequest( fuchsia::ui::scenic::Scenic* scenic) { fuchsia::ui::scenic::SessionPtr session; fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> listener_handle; auto listener_request = listener_handle.NewRequest(); scenic->CreateSession(session.NewRequest(), listener_handle.Bind()); return {std::move(session), std::move(listener_request)}; } Session::Session(fuchsia::ui::scenic::SessionPtr session, fidl::InterfaceRequest<fuchsia::ui::scenic::SessionListener> session_listener) : session_(std::move(session)), session_listener_binding_(this) { ZX_DEBUG_ASSERT(session_); if (session_listener.is_valid()) session_listener_binding_.Bind(std::move(session_listener)); } Session::Session(fuchsia::ui::scenic::Scenic* scenic) : session_listener_binding_(this) { ZX_DEBUG_ASSERT(scenic); scenic->CreateSession(session_.NewRequest(), session_listener_binding_.NewBinding()); } Session::Session(SessionPtrAndListenerRequest session_and_listener) : Session(std::move(session_and_listener.first), std::move(session_and_listener.second)) {} Session::~Session() { ZX_DEBUG_ASSERT_MSG(resource_count_ == 0, "Some resources outlived the session: %u", resource_count_); } uint32_t Session::AllocResourceId() { uint32_t resource_id = next_resource_id_++; ZX_DEBUG_ASSERT(resource_id); resource_count_++; return resource_id; } void Session::ReleaseResource(uint32_t resource_id) { resource_count_--; Enqueue(NewReleaseResourceCmd(resource_id)); } void Session::Enqueue(fuchsia::ui::gfx::Command command) { Enqueue(NewCommand(std::move(command))); } void Session::Enqueue(fuchsia::ui::input::Command command) { Enqueue(NewCommand(std::move(command))); } void Session::Enqueue(fuchsia::ui::scenic::Command command) { commands_.push_back(std::move(command)); if (commands_->size() >= kCommandsPerMessage || command.Which() == fuchsia::ui::scenic::Command::Tag::kInput) { Flush(); } } void Session::EnqueueAcquireFence(zx::event fence) { ZX_DEBUG_ASSERT(fence); acquire_fences_.push_back(std::move(fence)); } void Session::EnqueueReleaseFence(zx::event fence) { ZX_DEBUG_ASSERT(fence); release_fences_.push_back(std::move(fence)); } void Session::Flush() { ZX_DEBUG_ASSERT(session_); if (!commands_->empty()) { ZX_DEBUG_ASSERT(static_cast<bool>(commands_)); session_->Enqueue(std::move(commands_)); // After being moved, |commands_| is in a "valid but unspecified state"; // see http://en.cppreference.com/w/cpp/utility/move. Calling reset() makes // it safe to continue using. commands_.reset(); } } void Session::Present(uint64_t presentation_time, PresentCallback callback) { ZX_DEBUG_ASSERT(session_); Flush(); if (acquire_fences_.is_null()) acquire_fences_.resize(0u); if (release_fences_.is_null()) release_fences_.resize(0u); session_->Present(presentation_time, std::move(acquire_fences_), std::move(release_fences_), std::move(callback)); } void Session::HitTest(uint32_t node_id, const float ray_origin[3], const float ray_direction[3], HitTestCallback callback) { ZX_DEBUG_ASSERT(session_); fuchsia::ui::gfx::vec3 ray_origin_vec; ray_origin_vec.x = ray_origin[0]; ray_origin_vec.y = ray_origin[1]; ray_origin_vec.z = ray_origin[2]; fuchsia::ui::gfx::vec3 ray_direction_vec; ray_direction_vec.x = ray_direction[0]; ray_direction_vec.y = ray_direction[1]; ray_direction_vec.z = ray_direction[2]; session_->HitTest(node_id, std::move(ray_origin_vec), std::move(ray_direction_vec), std::move(callback)); } void Session::HitTestDeviceRay( const float ray_origin[3], const float ray_direction[3], fuchsia::ui::scenic::Session::HitTestDeviceRayCallback callback) { ZX_DEBUG_ASSERT(session_); fuchsia::ui::gfx::vec3 ray_origin_vec; ray_origin_vec.x = ray_origin[0]; ray_origin_vec.y = ray_origin[1]; ray_origin_vec.z = ray_origin[2]; fuchsia::ui::gfx::vec3 ray_direction_vec; ray_direction_vec.x = ray_direction[0]; ray_direction_vec.y = ray_direction[1]; ray_direction_vec.z = ray_direction[2]; session_->HitTestDeviceRay(std::move(ray_origin_vec), std::move(ray_direction_vec), std::move(callback)); } void Session::Unbind() { ZX_DEBUG_ASSERT(session_); ZX_DEBUG_ASSERT(!session_handle_); session_handle_ = session_.Unbind(); session_ = nullptr; } void Session::Rebind() { ZX_DEBUG_ASSERT(!session_); ZX_DEBUG_ASSERT(session_handle_); session_ = fuchsia::ui::scenic::SessionPtr(session_handle_.Bind()); session_handle_ = nullptr; } void Session::OnScenicError(fidl::StringPtr error) { // TODO(SCN-903): replace fprintf with SDK-approved logging mechanism. Also // remove "#include <stdio.h>". fprintf(stderr, "Session error: %s", error->c_str()); } void Session::OnScenicEvent( fidl::VectorPtr<fuchsia::ui::scenic::Event> events) { if (event_handler_) event_handler_(std::move(events)); } void Session::SetDebugName(const std::string& debug_name) { session_->SetDebugName(debug_name); } } // namespace scenic