// Copyright 2020 The Chromium 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 "cc/metrics/total_frame_counter.h"

#include "base/logging.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"

namespace cc {

TotalFrameCounter::TotalFrameCounter() = default;

void TotalFrameCounter::OnShow(base::TimeTicks timestamp) {
  DCHECK(last_shown_timestamp_.is_null());
  DCHECK(latest_interval_.is_zero());
  last_shown_timestamp_ = timestamp;
}

void TotalFrameCounter::OnHide(base::TimeTicks timestamp) {
  // It is possible to hide right after being shown before receiving any
  // BeginFrameArgs.
  if (!latest_interval_.is_zero())
    UpdateTotalFramesSinceLastVisible(timestamp);
  last_shown_timestamp_ = base::TimeTicks();
  latest_interval_ = base::TimeDelta();
}

void TotalFrameCounter::OnBeginFrame(const viz::BeginFrameArgs& args) {
  // In tests, it is possible to receive begin-frames when invisible. Ignore
  // these.
  if (last_shown_timestamp_.is_null())
    return;

  if (!latest_interval_.is_zero() && latest_interval_ != args.interval) {
    UpdateTotalFramesSinceLastVisible(args.frame_time);
    last_shown_timestamp_ = args.frame_time;
  }

  latest_interval_ = args.interval;
}

void TotalFrameCounter::Reset() {
  total_frames_ = 0;
  latest_interval_ = {};
  // If the compositor is visible, then update the visible timestamp to current
  // time.
  if (!last_shown_timestamp_.is_null())
    last_shown_timestamp_ = base::TimeTicks::Now();
}

void TotalFrameCounter::UpdateTotalFramesSinceLastVisible(
    base::TimeTicks until) {
  total_frames_ = ComputeTotalVisibleFrames(until);
}

size_t TotalFrameCounter::ComputeTotalVisibleFrames(
    base::TimeTicks until) const {
  DCHECK(!until.is_null());

  if (last_shown_timestamp_.is_null() || latest_interval_.is_zero()) {
    // The compositor may be currently invisible, or has just been made visible
    // but has yet to receive a BeginFrameArgs.
    return total_frames_;
  }

  DCHECK_GE(until, last_shown_timestamp_);
  auto frames_since =
      std::round((until - last_shown_timestamp_) / latest_interval_);
  return total_frames_ + frames_since;
}

}  // namespace cc
