1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/metrics/frame_sorter.h"
9 #include "cc/metrics/frame_info.h"
13 using FrameState = FrameSorter::FrameState;
15 void FrameState::OnBegin() {
19 void FrameState::OnAck(bool is_dropped) {
21 is_dropped_ |= is_dropped;
24 void FrameState::OnReset() {
25 should_ignore_ = true;
28 bool FrameState::IsComplete() const {
29 return (on_begin_counter == ack_counter);
32 FrameSorter::FrameSorter(InOrderBeginFramesCallback callback)
33 : flush_callback_(std::move(callback)) {
34 DCHECK(!flush_callback_.is_null());
36 FrameSorter::~FrameSorter() = default;
38 void FrameSorter::AddNewFrame(const viz::BeginFrameArgs& args) {
39 if (current_source_id_.has_value() &&
40 current_source_id_ > args.frame_id.source_id) {
43 if (current_source_id_.has_value() &&
44 current_source_id_ < args.frame_id.source_id) {
45 // The change in source_id can be as a result of crash on gpu process,
46 // which invalidates existing pending frames (no ack is expected).
50 if (!pending_frames_.empty()) {
51 const auto& last = pending_frames_.back();
52 DCHECK_LE(last.frame_id.sequence_number, args.frame_id.sequence_number);
54 current_source_id_ = args.frame_id.source_id;
56 // This condition prevents adding duplicate frames to pending_frames_
57 // as well as not re-adding a frame after it's removed from pending_frames_.
58 if (!frame_states_.count(args.frame_id))
59 pending_frames_.push_back(args);
60 frame_states_[args.frame_id].OnBegin();
62 // Remove the oldest frame until remaining pending frames are lower that
64 while (pending_frames_.size() > kPendingFramesMaxSize) {
65 const auto& first = pending_frames_.front();
66 frame_states_.erase(first.frame_id);
67 frame_infos_.erase(first.frame_id);
68 pending_frames_.pop_front();
72 void FrameSorter::AddFrameResult(const viz::BeginFrameArgs& args,
73 const FrameInfo& frame_info) {
74 if (pending_frames_.empty() || current_source_id_ > args.frame_id.source_id) {
75 // The change in source_id can be as a result of crash on gpu process,
76 // and as a result the corresponding frame to result does not exist.
80 // Early exit if expecting acks for frames, such as when:
81 // - This frame is already added to pending_frames_
82 // - When the frame was in pending_frames_ and was removed because of reset.
83 if (!frame_states_.count(args.frame_id))
86 const auto f = frame_infos_.find(args.frame_id);
87 if (f != frame_infos_.end()) {
88 f->second.MergeWith(frame_info);
90 frame_infos_[args.frame_id] = frame_info;
93 const bool is_dropped = frame_info.IsDroppedAffectingSmoothness();
94 auto& frame_state = frame_states_[args.frame_id];
95 frame_state.OnAck(is_dropped);
96 if (!frame_state.IsComplete()) {
99 if (frame_state.should_ignore()) {
100 // The associated frame in pending_frames_ was already removed in Reset().
101 frame_states_.erase(args.frame_id);
102 frame_infos_.erase(args.frame_id);
106 const auto& last_frame = pending_frames_.front();
107 if (last_frame.frame_id == args.frame_id) {
109 } else if (last_frame.frame_id.sequence_number <=
110 args.frame_id.sequence_number) {
111 // Checks if the corresponding frame to the result, exists in the
112 // pending_frames list.
113 DCHECK(std::binary_search(
114 pending_frames_.begin(), pending_frames_.end(), args,
115 [](const viz::BeginFrameArgs& one, const viz::BeginFrameArgs& two) {
116 return one.frame_id < two.frame_id;
118 << args.frame_id.ToString()
119 << pending_frames_.front().frame_id.ToString();
123 bool FrameSorter::IsAlreadyReportedDropped(const viz::BeginFrameId& id) const {
124 auto it = frame_states_.find(id);
125 if (it == frame_states_.end())
127 return it->second.is_dropped();
130 void FrameSorter::Reset() {
131 for (auto pending_frame : pending_frames_) {
132 const auto& frame_id = pending_frame.frame_id;
133 auto& frame_state = frame_states_[frame_id];
134 if (frame_state.IsComplete() && !frame_state.should_ignore()) {
135 flush_callback_.Run(pending_frame, frame_infos_[frame_id]);
136 frame_states_.erase(frame_id);
137 frame_infos_.erase(frame_id);
140 frame_state.OnReset();
142 pending_frames_.clear();
145 void FrameSorter::FlushFrames() {
146 DCHECK(!pending_frames_.empty());
147 size_t flushed_count = 0;
148 while (!pending_frames_.empty()) {
149 const auto& first = pending_frames_.front();
150 const auto& frame_id = first.frame_id;
151 auto& frame_state = frame_states_[frame_id];
152 if (!frame_state.IsComplete())
155 flush_callback_.Run(first, frame_infos_[frame_id]);
156 frame_states_.erase(frame_id);
157 frame_infos_.erase(frame_id);
158 pending_frames_.pop_front();
160 DCHECK_GT(flushed_count, 0u);