blob: 41d13a0b24b9f50ff5a2694b9ae5c0a9b5474b8b [file] [log] [blame]
// Copyright 2019 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/compositor_frame_reporting_controller.h"
#include "cc/metrics/compositor_frame_reporter.h"
#include "cc/metrics/latency_ukm_reporter.h"
#include "components/viz/common/frame_timing_details.h"
#include "components/viz/common/quads/compositor_frame_metadata.h"
namespace cc {
namespace {
using StageType = CompositorFrameReporter::StageType;
} // namespace
CompositorFrameReportingController::CompositorFrameReportingController(
bool is_single_threaded)
: is_single_threaded_(is_single_threaded),
latency_ukm_reporter_(std::make_unique<LatencyUkmReporter>()) {}
CompositorFrameReportingController::~CompositorFrameReportingController() {
base::TimeTicks now = Now();
for (int i = 0; i < PipelineStage::kNumPipelineStages; ++i) {
if (reporters_[i]) {
reporters_[i]->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame,
now);
}
}
for (auto& pair : submitted_compositor_frames_) {
pair.reporter->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kDidNotPresentFrame,
Now());
}
}
CompositorFrameReportingController::SubmittedCompositorFrame::
SubmittedCompositorFrame() = default;
CompositorFrameReportingController::SubmittedCompositorFrame::
SubmittedCompositorFrame(uint32_t frame_token,
std::unique_ptr<CompositorFrameReporter> reporter)
: frame_token(frame_token), reporter(std::move(reporter)) {}
CompositorFrameReportingController::SubmittedCompositorFrame::
~SubmittedCompositorFrame() = default;
CompositorFrameReportingController::SubmittedCompositorFrame::
SubmittedCompositorFrame(SubmittedCompositorFrame&& other) = default;
base::TimeTicks CompositorFrameReportingController::Now() const {
return base::TimeTicks::Now();
}
void CompositorFrameReportingController::WillBeginImplFrame() {
base::TimeTicks begin_time = Now();
if (reporters_[PipelineStage::kBeginImplFrame]) {
// If the the reporter is replaced in this stage, it means that Impl frame
// caused no damage.
reporters_[PipelineStage::kBeginImplFrame]->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame,
begin_time);
}
std::unique_ptr<CompositorFrameReporter> reporter =
std::make_unique<CompositorFrameReporter>(
&active_trackers_, latency_ukm_reporter_.get(), is_single_threaded_);
reporter->StartStage(StageType::kBeginImplFrameToSendBeginMainFrame,
begin_time);
reporters_[PipelineStage::kBeginImplFrame] = std::move(reporter);
}
void CompositorFrameReportingController::WillBeginMainFrame() {
if (reporters_[PipelineStage::kBeginImplFrame]) {
// We need to use .get() below because operator<< in std::unique_ptr is a
// C++20 feature.
DCHECK_NE(reporters_[PipelineStage::kBeginMainFrame].get(),
reporters_[PipelineStage::kBeginImplFrame].get());
reporters_[PipelineStage::kBeginImplFrame]->StartStage(
StageType::kSendBeginMainFrameToCommit, Now());
AdvanceReporterStage(PipelineStage::kBeginImplFrame,
PipelineStage::kBeginMainFrame);
} else {
// In this case we have already submitted the ImplFrame, but we received
// beginMain frame before next BeginImplFrame (Not reached the ImplFrame
// deadline yet). So will start a new reporter at BeginMainFrame.
std::unique_ptr<CompositorFrameReporter> reporter =
std::make_unique<CompositorFrameReporter>(&active_trackers_,
latency_ukm_reporter_.get(),
is_single_threaded_);
reporter->StartStage(StageType::kSendBeginMainFrameToCommit, Now());
reporters_[PipelineStage::kBeginMainFrame] = std::move(reporter);
}
}
void CompositorFrameReportingController::BeginMainFrameAborted() {
DCHECK(reporters_[PipelineStage::kBeginMainFrame]);
auto& begin_main_reporter = reporters_[PipelineStage::kBeginMainFrame];
begin_main_reporter->OnAbortBeginMainFrame();
// If the main-frame was aborted (e.g. there was no visible update), then
// advance to activate stage if the compositor has already made changes to
// the active tree (i.e. if impl-frame has finished).
if (begin_main_reporter->did_finish_impl_frame()) {
begin_main_reporter->StartStage(
StageType::kEndActivateToSubmitCompositorFrame, Now());
AdvanceReporterStage(PipelineStage::kBeginMainFrame,
PipelineStage::kActivate);
}
}
void CompositorFrameReportingController::WillCommit() {
DCHECK(reporters_[PipelineStage::kBeginMainFrame]);
reporters_[PipelineStage::kBeginMainFrame]->StartStage(StageType::kCommit,
Now());
}
void CompositorFrameReportingController::DidCommit() {
DCHECK(reporters_[PipelineStage::kBeginMainFrame]);
reporters_[PipelineStage::kBeginMainFrame]->StartStage(
StageType::kEndCommitToActivation, Now());
AdvanceReporterStage(PipelineStage::kBeginMainFrame, PipelineStage::kCommit);
}
void CompositorFrameReportingController::WillInvalidateOnImplSide() {
// Allows for activation without committing.
// TODO(alsan): Report latency of impl side invalidations.
next_activate_has_invalidation_ = true;
}
void CompositorFrameReportingController::WillActivate() {
DCHECK(reporters_[PipelineStage::kCommit] || next_activate_has_invalidation_);
if (!reporters_[PipelineStage::kCommit])
return;
reporters_[PipelineStage::kCommit]->StartStage(StageType::kActivation, Now());
}
void CompositorFrameReportingController::DidActivate() {
DCHECK(reporters_[PipelineStage::kCommit] || next_activate_has_invalidation_);
next_activate_has_invalidation_ = false;
if (!reporters_[PipelineStage::kCommit])
return;
reporters_[PipelineStage::kCommit]->StartStage(
StageType::kEndActivateToSubmitCompositorFrame, Now());
AdvanceReporterStage(PipelineStage::kCommit, PipelineStage::kActivate);
}
void CompositorFrameReportingController::DidSubmitCompositorFrame(
uint32_t frame_token) {
// If there is no reporter in active stage and there exists a finished
// BeginImplFrame reporter (i.e. if impl-frame has finished), then advance it
// to the activate stage.
if (!reporters_[PipelineStage::kActivate] &&
reporters_[PipelineStage::kBeginImplFrame]) {
auto& begin_impl_frame = reporters_[PipelineStage::kBeginImplFrame];
if (begin_impl_frame->did_finish_impl_frame()) {
begin_impl_frame->StartStage(
StageType::kEndActivateToSubmitCompositorFrame,
begin_impl_frame->impl_frame_finish_time());
AdvanceReporterStage(PipelineStage::kBeginImplFrame,
PipelineStage::kActivate);
}
}
if (!reporters_[PipelineStage::kActivate])
return;
std::unique_ptr<CompositorFrameReporter> submitted_reporter =
std::move(reporters_[PipelineStage::kActivate]);
submitted_reporter->StartStage(
StageType::kSubmitCompositorFrameToPresentationCompositorFrame, Now());
submitted_compositor_frames_.emplace_back(frame_token,
std::move(submitted_reporter));
}
void CompositorFrameReportingController::OnFinishImplFrame() {
if (reporters_[PipelineStage::kBeginImplFrame]) {
reporters_[PipelineStage::kBeginImplFrame]->OnFinishImplFrame(Now());
} else if (reporters_[PipelineStage::kBeginMainFrame]) {
auto& begin_main_reporter = reporters_[PipelineStage::kBeginMainFrame];
begin_main_reporter->OnFinishImplFrame(Now());
// If the main-frame was aborted (e.g. there was no visible update), then
// advance to activate stage if the compositor has already made changes to
// the active tree (i.e. if impl-frame has finished).
if (begin_main_reporter->did_abort_main_frame()) {
begin_main_reporter->StartStage(
StageType::kEndActivateToSubmitCompositorFrame, Now());
AdvanceReporterStage(PipelineStage::kBeginMainFrame,
PipelineStage::kActivate);
}
}
}
void CompositorFrameReportingController::DidPresentCompositorFrame(
uint32_t frame_token,
const viz::FrameTimingDetails& details) {
while (!submitted_compositor_frames_.empty()) {
auto submitted_frame = submitted_compositor_frames_.begin();
if (viz::FrameTokenGT(submitted_frame->frame_token, frame_token))
break;
auto termination_status =
CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame;
if (submitted_frame->frame_token != frame_token)
termination_status =
CompositorFrameReporter::FrameTerminationStatus::kDidNotPresentFrame;
submitted_frame->reporter->SetVizBreakdown(details);
submitted_frame->reporter->TerminateFrame(
termination_status, details.presentation_feedback.timestamp);
submitted_compositor_frames_.erase(submitted_frame);
}
}
void CompositorFrameReportingController::SetBlinkBreakdown(
std::unique_ptr<BeginMainFrameMetrics> details) {
DCHECK(reporters_[PipelineStage::kBeginMainFrame]);
reporters_[PipelineStage::kBeginMainFrame]->SetBlinkBreakdown(
std::move(details));
}
void CompositorFrameReportingController::AddActiveTracker(
FrameSequenceTrackerType type) {
active_trackers_.insert(type);
}
void CompositorFrameReportingController::RemoveActiveTracker(
FrameSequenceTrackerType type) {
active_trackers_.erase(type);
}
void CompositorFrameReportingController::AdvanceReporterStage(
PipelineStage start,
PipelineStage target) {
if (reporters_[target]) {
reporters_[target]->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kReplacedByNewReporter,
Now());
}
reporters_[target] = std::move(reporters_[start]);
}
void CompositorFrameReportingController::SetUkmManager(UkmManager* manager) {
latency_ukm_reporter_->SetUkmManager(manager);
}
} // namespace cc