xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/FrameTracker.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  * Copyright (C) 2012 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 // TODO(b/129481165): remove the #pragma below and fix conversion issues
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wconversion"
20 
21 #include <inttypes.h>
22 
23 #include <android-base/stringprintf.h>
24 #include <android/log.h>
25 
26 #include <ui/FrameStats.h>
27 
28 #include "FrameTracker.h"
29 
30 namespace android {
31 
FrameTracker()32 FrameTracker::FrameTracker() : mOffset(0), mNumFences(0), mDisplayPeriod(0) {}
33 
setDesiredPresentTime(nsecs_t presentTime)34 void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) {
35     Mutex::Autolock lock(mMutex);
36     mFrameRecords[mOffset].desiredPresentTime = presentTime;
37 }
38 
setFrameReadyTime(nsecs_t readyTime)39 void FrameTracker::setFrameReadyTime(nsecs_t readyTime) {
40     Mutex::Autolock lock(mMutex);
41     mFrameRecords[mOffset].frameReadyTime = readyTime;
42 }
43 
setFrameReadyFence(std::shared_ptr<FenceTime> && readyFence)44 void FrameTracker::setFrameReadyFence(
45         std::shared_ptr<FenceTime>&& readyFence) {
46     Mutex::Autolock lock(mMutex);
47     mFrameRecords[mOffset].frameReadyFence = std::move(readyFence);
48     mNumFences++;
49 }
50 
setActualPresentTime(nsecs_t presentTime)51 void FrameTracker::setActualPresentTime(nsecs_t presentTime) {
52     Mutex::Autolock lock(mMutex);
53     mFrameRecords[mOffset].actualPresentTime = presentTime;
54 }
55 
setActualPresentFence(const std::shared_ptr<FenceTime> & readyFence)56 void FrameTracker::setActualPresentFence(const std::shared_ptr<FenceTime>& readyFence) {
57     Mutex::Autolock lock(mMutex);
58     mFrameRecords[mOffset].actualPresentFence = readyFence;
59     mNumFences++;
60 }
61 
setDisplayRefreshPeriod(nsecs_t displayPeriod)62 void FrameTracker::setDisplayRefreshPeriod(nsecs_t displayPeriod) {
63     Mutex::Autolock lock(mMutex);
64     mDisplayPeriod = displayPeriod;
65 }
66 
advanceFrame()67 void FrameTracker::advanceFrame() {
68     Mutex::Autolock lock(mMutex);
69 
70     // Advance to the next frame.
71     mOffset = (mOffset+1) % NUM_FRAME_RECORDS;
72     mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
73     mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
74     mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
75 
76     if (mFrameRecords[mOffset].frameReadyFence != nullptr) {
77         // We're clobbering an unsignaled fence, so we need to decrement the
78         // fence count.
79         mFrameRecords[mOffset].frameReadyFence = nullptr;
80         mNumFences--;
81     }
82 
83     if (mFrameRecords[mOffset].actualPresentFence != nullptr) {
84         // We're clobbering an unsignaled fence, so we need to decrement the
85         // fence count.
86         mFrameRecords[mOffset].actualPresentFence = nullptr;
87         mNumFences--;
88     }
89 }
90 
clearStats()91 void FrameTracker::clearStats() {
92     Mutex::Autolock lock(mMutex);
93     for (size_t i = 0; i < NUM_FRAME_RECORDS; i++) {
94         mFrameRecords[i].desiredPresentTime = 0;
95         mFrameRecords[i].frameReadyTime = 0;
96         mFrameRecords[i].actualPresentTime = 0;
97         mFrameRecords[i].frameReadyFence.reset();
98         mFrameRecords[i].actualPresentFence.reset();
99     }
100     mNumFences = 0;
101     mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
102     mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
103     mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
104 }
105 
getStats(FrameStats * outStats) const106 void FrameTracker::getStats(FrameStats* outStats) const {
107     Mutex::Autolock lock(mMutex);
108     processFencesLocked();
109 
110     outStats->refreshPeriodNano = mDisplayPeriod;
111 
112     const size_t offset = mOffset;
113     for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
114         const size_t index = (offset + i) % NUM_FRAME_RECORDS;
115 
116         // Skip frame records with no data (if buffer not yet full).
117         if (mFrameRecords[index].desiredPresentTime == 0) {
118             continue;
119         }
120 
121         nsecs_t desiredPresentTimeNano = mFrameRecords[index].desiredPresentTime;
122         outStats->desiredPresentTimesNano.push_back(desiredPresentTimeNano);
123 
124         nsecs_t actualPresentTimeNano = mFrameRecords[index].actualPresentTime;
125         outStats->actualPresentTimesNano.push_back(actualPresentTimeNano);
126 
127         nsecs_t frameReadyTimeNano = mFrameRecords[index].frameReadyTime;
128         outStats->frameReadyTimesNano.push_back(frameReadyTimeNano);
129     }
130 }
131 
processFencesLocked() const132 void FrameTracker::processFencesLocked() const {
133     FrameRecord* records = const_cast<FrameRecord*>(mFrameRecords);
134     int& numFences = const_cast<int&>(mNumFences);
135 
136     for (int i = 1; i < NUM_FRAME_RECORDS && numFences > 0; i++) {
137         size_t idx = (mOffset + NUM_FRAME_RECORDS - i) % NUM_FRAME_RECORDS;
138 
139         const std::shared_ptr<FenceTime>& rfence = records[idx].frameReadyFence;
140         if (rfence != nullptr) {
141             records[idx].frameReadyTime = rfence->getSignalTime();
142             if (records[idx].frameReadyTime < INT64_MAX) {
143                 records[idx].frameReadyFence = nullptr;
144                 numFences--;
145             }
146         }
147 
148         const std::shared_ptr<FenceTime>& pfence =
149                 records[idx].actualPresentFence;
150         if (pfence != nullptr) {
151             records[idx].actualPresentTime = pfence->getSignalTime();
152             if (records[idx].actualPresentTime < INT64_MAX) {
153                 records[idx].actualPresentFence = nullptr;
154                 numFences--;
155             }
156         }
157     }
158 }
159 
isFrameValidLocked(size_t idx) const160 bool FrameTracker::isFrameValidLocked(size_t idx) const {
161     return mFrameRecords[idx].actualPresentTime > 0 &&
162             mFrameRecords[idx].actualPresentTime < INT64_MAX;
163 }
164 
dumpStats(std::string & result) const165 void FrameTracker::dumpStats(std::string& result) const {
166     Mutex::Autolock lock(mMutex);
167     processFencesLocked();
168 
169     const size_t o = mOffset;
170     for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
171         const size_t index = (o+i) % NUM_FRAME_RECORDS;
172         base::StringAppendF(&result, "%" PRId64 "\t%" PRId64 "\t%" PRId64 "\n",
173                             mFrameRecords[index].desiredPresentTime,
174                             mFrameRecords[index].actualPresentTime,
175                             mFrameRecords[index].frameReadyTime);
176     }
177     result.append("\n");
178 }
179 
180 } // namespace android
181 
182 // TODO(b/129481165): remove the #pragma below and fix conversion issues
183 #pragma clang diagnostic pop // ignored "-Wconversion"
184