| // Copyright 2022 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 "src/embedder/flatland_connection.h" |
| |
| #include <lib/fit/function.h> |
| #include <lib/syslog/global.h> |
| #include <zircon/status.h> |
| |
| #include "src/embedder/logging.h" |
| |
| namespace embedder { |
| |
| FlatlandConnection::FlatlandConnection(std::string debug_name, |
| fuchsia::ui::composition::FlatlandHandle flatland, |
| std::function<void()> on_error_callback, |
| OnFramePresentedCallback on_frame_presented_callback) |
| : flatland_(flatland.Bind()), |
| on_error_callback_(on_error_callback), |
| on_frame_presented_callback_(std::move(on_frame_presented_callback)) { |
| flatland_.set_error_handler([callback = on_error_callback_](zx_status_t status) { |
| FX_LOGF(ERROR, kLogTag, "Flatland disconnected: %s", zx_status_get_string(status)); |
| callback(); |
| }); |
| flatland_->SetDebugName(debug_name); |
| flatland_.events().OnError = fit::bind_member(this, &FlatlandConnection::OnError); |
| flatland_.events().OnFramePresented = |
| fit::bind_member(this, &FlatlandConnection::OnFramePresented); |
| flatland_.events().OnNextFrameBegin = |
| fit::bind_member(this, &FlatlandConnection::OnNextFrameBegin); |
| } |
| |
| FlatlandConnection::~FlatlandConnection() = default; |
| |
| // This method is called from the raster thread. |
| void FlatlandConnection::Present() { |
| if (present_credits_ > 0) { |
| DoPresent(); |
| } else { |
| present_pending_ = true; |
| } |
| } |
| |
| // This method is called from the raster thread. |
| void FlatlandConnection::DoPresent() { |
| if (present_credits_ == 0) { |
| FX_LOG(FATAL, kLogTag, "Tried to DoPresent() with 0 present credits."); |
| return; |
| } |
| |
| --present_credits_; |
| |
| fuchsia::ui::composition::PresentArgs present_args; |
| // TODO(http://fxbug.dev/94000): Compute a better presentation time. |
| present_args.set_requested_presentation_time(0); |
| present_args.set_acquire_fences(std::move(acquire_fences_)); |
| present_args.set_release_fences(std::move(previous_present_release_fences_)); |
| present_args.set_unsquashable(false); |
| flatland_->Present(std::move(present_args)); |
| |
| // In Flatland, release fences apply to the content of the previous present. |
| // Keeping track of the old frame's release fences and swapping ensure we set |
| // the correct ones for VulkanSurface's interpretation. |
| previous_present_release_fences_.clear(); |
| previous_present_release_fences_.swap(current_present_release_fences_); |
| acquire_fences_.clear(); |
| } |
| |
| void FlatlandConnection::OnError(fuchsia::ui::composition::FlatlandError error) { |
| FX_LOGF(ERROR, kLogTag, "Flatland error: %d", static_cast<int>(error)); |
| on_error_callback_(); |
| } |
| |
| // This method is called from the raster thread. |
| void FlatlandConnection::OnNextFrameBegin(fuchsia::ui::composition::OnNextFrameBeginValues values) { |
| present_credits_ += values.additional_present_credits(); |
| |
| if (present_pending_ && present_credits_ > 0) { |
| DoPresent(); |
| present_pending_ = false; |
| } |
| |
| // TODO(akbiggs): Implement vsyncing logic from |
| // https://github.com/flutter/engine/blob/83db012e3ff4e51588772067b59d499bfd44ad2e/shell/platform/fuchsia/flutter/flatland_connection.cc#L120. |
| } |
| |
| // This method is called from the raster thread. |
| void FlatlandConnection::OnFramePresented(fuchsia::scenic::scheduling::FramePresentedInfo info) { |
| on_frame_presented_callback_(std::move(info)); |
| } |
| |
| // This method is called from the raster thread. |
| void FlatlandConnection::EnqueueAcquireFence(zx::event fence) { |
| acquire_fences_.push_back(std::move(fence)); |
| } |
| |
| // This method is called from the raster thread. |
| void FlatlandConnection::EnqueueReleaseFence(zx::event fence) { |
| current_present_release_fences_.push_back(std::move(fence)); |
| } |
| |
| } // namespace embedder |