chromium/ui/ozone/platform/flatland/flatland_connection.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/ozone/platform/flatland/flatland_connection.h"

#include <lib/sys/cpp/component_context.h>

#include <string_view>

#include "base/check.h"
#include "base/check_op.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/process_context.h"
#include "base/functional/bind.h"
#include "base/logging.h"

namespace ui {

FlatlandConnection::FlatlandConnection(std::string_view debug_name,
                                       OnErrorCallback error_callback) {
  zx_status_t status =
      base::ComponentContextForProcess()
          ->svc()
          ->Connect<fuchsia::ui::composition::Flatland>(flatland_.NewRequest());
  if (status != ZX_OK) {
    ZX_LOG(FATAL, status) << "Failed to connect to Flatland";
  }

  flatland_->SetDebugName(static_cast<std::string>(debug_name));
  DCHECK(error_callback);
  flatland_.events().OnError =
      [callback = std::move(error_callback)](
          fuchsia::ui::composition::FlatlandError error) mutable {
        std::move(callback).Run(std::move(error));
      };
  flatland_.events().OnFramePresented =
      fit::bind_member(this, &FlatlandConnection::OnFramePresented);
  flatland_.events().OnNextFrameBegin =
      fit::bind_member(this, &FlatlandConnection::OnNextFrameBegin);
}

FlatlandConnection::~FlatlandConnection() = default;

void FlatlandConnection::Present() {
  fuchsia::ui::composition::PresentArgs present_args;
  present_args.set_requested_presentation_time(0);
  present_args.set_acquire_fences({});
  present_args.set_release_fences({});
  present_args.set_unsquashable(false);
  Present(std::move(present_args),
          base::BindOnce([](base::TimeTicks, base::TimeDelta) {}));
}

void FlatlandConnection::Present(
    fuchsia::ui::composition::PresentArgs present_args,
    OnFramePresentedCallback callback) {
  if (present_credits_ == 0) {
    pending_presents_.emplace(std::move(present_args), std::move(callback));
    DCHECK_LE(pending_presents_.size(), 3u)
        << "Renderer is queueing up more frames than expected.";
    return;
  }
  --present_credits_;

  // In Flatland, release fences apply to the content of the previous present.
  // Keeping track of the previous frame's release fences and swapping ensure we
  // set the correct ones.
  present_args.mutable_release_fences()->swap(previous_present_release_fences_);

  flatland_->Present(std::move(present_args));
  presented_callbacks_.push(std::move(callback));
}

void FlatlandConnection::OnNextFrameBegin(
    fuchsia::ui::composition::OnNextFrameBeginValues values) {
  // Calculate the presentation interval by looking at the 2 closest
  // presentation times.
  if (values.has_future_presentation_infos() &&
      values.future_presentation_infos().size() > 1) {
    presentation_interval_ =
        base::TimeTicks::FromZxTime(
            values.future_presentation_infos()[1].presentation_time()) -
        base::TimeTicks::FromZxTime(
            values.future_presentation_infos()[0].presentation_time());
  }
  present_credits_ += values.additional_present_credits();
  if (present_credits_ && !pending_presents_.empty()) {
    // Only iterate over the elements once, because they may be added back to
    // the queue.
    while (present_credits_ && !pending_presents_.empty()) {
      PendingPresent present = std::move(pending_presents_.front());
      pending_presents_.pop();
      Present(std::move(present.present_args), std::move(present.callback));
    }
  }
}

void FlatlandConnection::OnFramePresented(
    fuchsia::scenic::scheduling::FramePresentedInfo info) {
  for (size_t i = 0; i < info.presentation_infos.size(); ++i) {
    std::move(presented_callbacks_.front())
        .Run(base::TimeTicks::FromZxTime(info.actual_presentation_time),
             presentation_interval_);
    presented_callbacks_.pop();
  }
}

FlatlandConnection::PendingPresent::PendingPresent(
    fuchsia::ui::composition::PresentArgs present_args,
    OnFramePresentedCallback callback)
    : present_args(std::move(present_args)), callback(std::move(callback)) {}
FlatlandConnection::PendingPresent::~PendingPresent() = default;

FlatlandConnection::PendingPresent::PendingPresent(PendingPresent&& other) =
    default;
FlatlandConnection::PendingPresent&
FlatlandConnection::PendingPresent::operator=(PendingPresent&&) = default;

}  // namespace ui