blob: c95440a5ae55fc64d18af0649f9a1a26fd8cb03a [file] [log] [blame]
Adithya Srinivasanf279e042020-08-17 14:56:27 -07001/*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#undef LOG_TAG
18#define LOG_TAG "FrameTimeline"
19#define ATRACE_TAG ATRACE_TAG_GRAPHICS
20
21#include "FrameTimeline.h"
22#include <android-base/stringprintf.h>
23#include <cinttypes>
24
25namespace android::frametimeline::impl {
26
27using base::StringAppendF;
28
29int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
30 std::lock_guard<std::mutex> lock(mMutex);
31 const int64_t assignedToken = mCurrentToken++;
32 mPredictions[assignedToken] = predictions;
33 mTokens.emplace_back(std::make_pair(assignedToken, systemTime()));
34 flushTokens(systemTime());
35 return assignedToken;
36}
37
38std::optional<TimelineItem> TokenManager::getPredictionsForToken(int64_t token) {
39 std::lock_guard<std::mutex> lock(mMutex);
40 flushTokens(systemTime());
41 auto predictionsIterator = mPredictions.find(token);
42 if (predictionsIterator != mPredictions.end()) {
43 return predictionsIterator->second;
44 }
45 return {};
46}
47
48void TokenManager::flushTokens(nsecs_t flushTime) {
49 for (size_t i = 0; i < mTokens.size(); i++) {
50 if (flushTime - mTokens[i].second >= kMaxRetentionTime) {
51 mPredictions.erase(mTokens[i].first);
52 mTokens.erase(mTokens.begin() + static_cast<int>(i));
53 --i;
54 } else {
55 // Tokens are ordered by time. If i'th token is within the retention time, then the
56 // i+1'th token will also be within retention time.
57 break;
58 }
59 }
60}
61
62SurfaceFrame::SurfaceFrame(const std::string& layerName, PredictionState predictionState,
63 frametimeline::TimelineItem&& predictions)
64 : mLayerName(layerName),
65 mPresentState(PresentState::Unknown),
66 mPredictionState(predictionState),
67 mPredictions(predictions),
68 mActuals({0, 0, 0}),
69 mActualQueueTime(0) {}
70
71void SurfaceFrame::setPresentState(PresentState state) {
72 std::lock_guard<std::mutex> lock(mMutex);
73 mPresentState = state;
74}
75
76PredictionState SurfaceFrame::getPredictionState() {
77 std::lock_guard<std::mutex> lock(mMutex);
78 return mPredictionState;
79}
80
81SurfaceFrame::PresentState SurfaceFrame::getPresentState() {
82 std::lock_guard<std::mutex> lock(mMutex);
83 return mPresentState;
84}
85
86TimelineItem SurfaceFrame::getActuals() {
87 std::lock_guard<std::mutex> lock(mMutex);
88 return mActuals;
89}
90
91void SurfaceFrame::setActuals(frametimeline::TimelineItem&& actuals) {
92 std::lock_guard<std::mutex> lock(mMutex);
93 mActuals = actuals;
94}
95
96void SurfaceFrame::setPresentTime(nsecs_t presentTime) {
97 std::lock_guard<std::mutex> lock(mMutex);
98 mActuals.presentTime = presentTime;
99}
100
101void SurfaceFrame::dump(std::string& result) {
102 std::lock_guard<std::mutex> lock(mMutex);
103 StringAppendF(&result, "Predicted Start Time : %" PRId64 "\n", mPredictions.startTime);
104 StringAppendF(&result, "Actual Start Time : %" PRId64 "\n", mActuals.startTime);
105 StringAppendF(&result, "Actual Queue Time : %" PRId64 "\n", mActualQueueTime);
106 StringAppendF(&result, "Predicted Render Complete Time : %" PRId64 "\n", mPredictions.endTime);
107 StringAppendF(&result, "Actual Render Complete Time : %" PRId64 "\n", mActuals.endTime);
108 StringAppendF(&result, "Predicted Present Time : %" PRId64 "\n", mPredictions.presentTime);
109 StringAppendF(&result, "Actual Present Time : %" PRId64 "\n", mActuals.presentTime);
110}
111
112FrameTimeline::FrameTimeline() : mCurrentDisplayFrame(std::make_shared<DisplayFrame>()) {}
113
114FrameTimeline::DisplayFrame::DisplayFrame()
115 : surfaceFlingerPredictions(TimelineItem()),
116 surfaceFlingerActuals(TimelineItem()),
117 predictionState(PredictionState::None) {
118 this->surfaceFrames.reserve(kNumSurfaceFramesInitial);
119}
120
121std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
122 const std::string& layerName, std::optional<int64_t> token) {
123 if (!token) {
124 return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::None,
125 TimelineItem());
126 }
127 std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token);
128 if (predictions) {
129 return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Valid,
130 std::move(*predictions));
131 }
132 return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Expired,
133 TimelineItem());
134}
135
136void FrameTimeline::addSurfaceFrame(
137 std::unique_ptr<android::frametimeline::SurfaceFrame> surfaceFrame,
138 SurfaceFrame::PresentState state) {
139 surfaceFrame->setPresentState(state);
140 std::unique_ptr<impl::SurfaceFrame> implSurfaceFrame(
141 static_cast<impl::SurfaceFrame*>(surfaceFrame.release()));
142 std::lock_guard<std::mutex> lock(mMutex);
143 mCurrentDisplayFrame->surfaceFrames.push_back(std::move(implSurfaceFrame));
144}
145
146void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) {
147 const std::optional<TimelineItem> prediction = mTokenManager.getPredictionsForToken(token);
148 std::lock_guard<std::mutex> lock(mMutex);
149 if (!prediction) {
150 mCurrentDisplayFrame->predictionState = PredictionState::Expired;
151 } else {
152 mCurrentDisplayFrame->surfaceFlingerPredictions = *prediction;
153 }
154 mCurrentDisplayFrame->surfaceFlingerActuals.startTime = wakeUpTime;
155}
156
157void FrameTimeline::setSfPresent(nsecs_t sfPresentTime,
158 const std::shared_ptr<FenceTime>& presentFence) {
159 std::lock_guard<std::mutex> lock(mMutex);
160 mCurrentDisplayFrame->surfaceFlingerActuals.endTime = sfPresentTime;
161 mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame));
162 flushPendingPresentFences();
163 finalizeCurrentDisplayFrame();
164}
165
166void FrameTimeline::flushPendingPresentFences() {
167 for (size_t i = 0; i < mPendingPresentFences.size(); i++) {
168 const auto& pendingPresentFence = mPendingPresentFences[i];
169 nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
170 if (pendingPresentFence.first && pendingPresentFence.first->isValid()) {
171 signalTime = pendingPresentFence.first->getSignalTime();
172 if (signalTime == Fence::SIGNAL_TIME_PENDING) {
173 continue;
174 }
175 }
176 if (signalTime != Fence::SIGNAL_TIME_INVALID) {
177 auto& displayFrame = pendingPresentFence.second;
178 displayFrame->surfaceFlingerActuals.presentTime = signalTime;
179 for (auto& surfaceFrame : displayFrame->surfaceFrames) {
180 if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) {
181 // Only presented SurfaceFrames need to be updated
182 surfaceFrame->setPresentTime(signalTime);
183 }
184 }
185 }
186
187 mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i));
188 --i;
189 }
190}
191
192void FrameTimeline::finalizeCurrentDisplayFrame() {
193 while (mDisplayFrames.size() >= kMaxDisplayFrames) {
194 // We maintain only a fixed number of frames' data. Pop older frames
195 mDisplayFrames.pop_front();
196 }
197 mDisplayFrames.push_back(mCurrentDisplayFrame);
198 mCurrentDisplayFrame.reset();
199 mCurrentDisplayFrame = std::make_shared<DisplayFrame>();
200}
201
202void FrameTimeline::dump(std::string& result) {
203 std::lock_guard<std::mutex> lock(mMutex);
204 StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size());
205 for (const auto& displayFrame : mDisplayFrames) {
206 StringAppendF(&result, "---Display Frame---\n");
207 StringAppendF(&result, "Predicted SF wake time : %" PRId64 "\n",
208 displayFrame->surfaceFlingerPredictions.startTime);
209 StringAppendF(&result, "Actual SF wake time : %" PRId64 "\n",
210 displayFrame->surfaceFlingerActuals.startTime);
211 StringAppendF(&result, "Predicted SF Complete time : %" PRId64 "\n",
212 displayFrame->surfaceFlingerPredictions.endTime);
213 StringAppendF(&result, "Actual SF Complete time : %" PRId64 "\n",
214 displayFrame->surfaceFlingerActuals.endTime);
215 StringAppendF(&result, "Predicted Present time : %" PRId64 "\n",
216 displayFrame->surfaceFlingerPredictions.presentTime);
217 StringAppendF(&result, "Actual Present time : %" PRId64 "\n",
218 displayFrame->surfaceFlingerActuals.presentTime);
219 for (size_t i = 0; i < displayFrame->surfaceFrames.size(); i++) {
220 StringAppendF(&result, "Surface frame - %" PRId32 "\n", (int)i);
221 displayFrame->surfaceFrames[i]->dump(result);
222 }
223 }
224}
225
226} // namespace android::frametimeline::impl