[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / metrics / frame_sorter.cc
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.
4
5 #include "cc/metrics/frame_sorter.h"
6
7 #include <utility>
8
9 #include "cc/metrics/frame_info.h"
10
11 namespace cc {
12
13 using FrameState = FrameSorter::FrameState;
14
15 void FrameState::OnBegin() {
16   on_begin_counter++;
17 }
18
19 void FrameState::OnAck(bool is_dropped) {
20   ack_counter++;
21   is_dropped_ |= is_dropped;
22 }
23
24 void FrameState::OnReset() {
25   should_ignore_ = true;
26 }
27
28 bool FrameState::IsComplete() const {
29   return (on_begin_counter == ack_counter);
30 }
31
32 FrameSorter::FrameSorter(InOrderBeginFramesCallback callback)
33     : flush_callback_(std::move(callback)) {
34   DCHECK(!flush_callback_.is_null());
35 }
36 FrameSorter::~FrameSorter() = default;
37
38 void FrameSorter::AddNewFrame(const viz::BeginFrameArgs& args) {
39   if (current_source_id_.has_value() &&
40       current_source_id_ > args.frame_id.source_id) {
41     return;
42   }
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).
47     Reset();
48   }
49
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);
53   }
54   current_source_id_ = args.frame_id.source_id;
55
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();
61
62   // Remove the oldest frame until remaining pending frames are lower that
63   // than the limit
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();
69   }
70 }
71
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.
77     return;
78   }
79
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))
84     return;
85
86   const auto f = frame_infos_.find(args.frame_id);
87   if (f != frame_infos_.end()) {
88     f->second.MergeWith(frame_info);
89   } else {
90     frame_infos_[args.frame_id] = frame_info;
91   }
92
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()) {
97     return;
98   }
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);
103     return;
104   }
105
106   const auto& last_frame = pending_frames_.front();
107   if (last_frame.frame_id == args.frame_id) {
108     FlushFrames();
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;
117         }))
118         << args.frame_id.ToString()
119         << pending_frames_.front().frame_id.ToString();
120   }
121 }
122
123 bool FrameSorter::IsAlreadyReportedDropped(const viz::BeginFrameId& id) const {
124   auto it = frame_states_.find(id);
125   if (it == frame_states_.end())
126     return false;
127   return it->second.is_dropped();
128 }
129
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);
138       continue;
139     }
140     frame_state.OnReset();
141   }
142   pending_frames_.clear();
143 }
144
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())
153       break;
154     ++flushed_count;
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();
159   }
160   DCHECK_GT(flushed_count, 0u);
161 }
162
163 }  // namespace cc