blob: b1f479faadffedd22dd2f12e16f3aa965b4c8e6b [file] [log] [blame]
John Reckba6adf62015-02-19 14:36:50 -08001/*
2 * Copyright (C) 2015 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#ifndef FRAMEINFO_H_
17#define FRAMEINFO_H_
18
John Reckba6adf62015-02-19 14:36:50 -080019#include <cutils/compiler.h>
Ady Abrahame088dcd2023-08-10 11:45:58 -070020#include <memory.h>
John Reckba6adf62015-02-19 14:36:50 -080021#include <utils/Timers.h>
22
Siarhei Vishniakouefed1662020-11-30 10:30:52 -100023#include <array>
Ady Abrahame088dcd2023-08-10 11:45:58 -070024#include <optional>
John Reck4db3d172015-06-02 15:58:43 -070025#include <string>
John Reckba6adf62015-02-19 14:36:50 -080026
Ady Abrahame088dcd2023-08-10 11:45:58 -070027#include "SkippedFrameInfo.h"
28#include "utils/Macros.h"
29
John Reckba6adf62015-02-19 14:36:50 -080030namespace android {
31namespace uirenderer {
32
Melody Hsu92b519b2025-02-05 22:01:40 +000033// This value must be in sync with `FRAME_INFO_SIZE` in FrameInfo.Java
34static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 13;
John Reckba6adf62015-02-19 14:36:50 -080035
John Reckc87be992015-02-20 10:57:22 -080036enum class FrameInfoIndex {
Chris Craik1b54fb22015-06-02 17:40:58 -070037 Flags = 0,
Steven Thomas6fabb5a2020-08-21 16:56:08 -070038 FrameTimelineVsyncId,
Chris Craik1b54fb22015-06-02 17:40:58 -070039 IntendedVsync,
40 Vsync,
Siarhei Vishniakou4bcbffd2021-02-17 06:19:36 +000041 InputEventId,
Chris Craik1b54fb22015-06-02 17:40:58 -070042 HandleInputStart,
43 AnimationStart,
44 PerformTraversalsStart,
45 DrawStart,
Ady Abrahamdfb13982020-10-05 17:59:09 -070046 FrameDeadline,
Bo Liu027b2182021-03-18 16:50:38 -040047 FrameStartTime,
Jorim Jaggi10f328c2021-01-19 00:08:02 +010048 FrameInterval,
John Reckba6adf62015-02-19 14:36:50 -080049 // End of UI frame info
50
Melody Hsu92b519b2025-02-05 22:01:40 +000051 // The target workload duration based on the original frame deadline and
52 // and intended vsync. Counted in UI_THREAD_FRAME_INFO_SIZE so its value
53 // can be set in setVsync().
54 WorkloadTarget,
55
John Reckbe3fba02015-07-06 13:49:58 -070056 SyncQueued,
57
Chris Craik1b54fb22015-06-02 17:40:58 -070058 SyncStart,
59 IssueDrawCommandsStart,
60 SwapBuffers,
61 FrameCompleted,
John Reckba6adf62015-02-19 14:36:50 -080062
John Reck2d5b8d72016-07-28 15:36:11 -070063 DequeueBufferDuration,
64 QueueBufferDuration,
65
Stan Iliev7203e1f2019-07-25 13:12:02 -040066 GpuCompleted,
Jorim Jaggi71db8892021-02-03 23:19:29 +010067 SwapBuffersCompleted,
Siarhei Vishniakou4bcbffd2021-02-17 06:19:36 +000068 DisplayPresentTime,
Alec Mouri3afb3972022-05-27 22:03:11 +000069 CommandSubmissionCompleted,
Stan Iliev7203e1f2019-07-25 13:12:02 -040070
John Reckba6adf62015-02-19 14:36:50 -080071 // Must be the last value!
John Reck65ddb152016-08-02 09:38:26 -070072 // Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT
Chris Craik1b54fb22015-06-02 17:40:58 -070073 NumIndexes
John Reckc87be992015-02-20 10:57:22 -080074};
John Reckba6adf62015-02-19 14:36:50 -080075
Siarhei Vishniakou4bcbffd2021-02-17 06:19:36 +000076extern const std::array<const char*, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames;
John Reck4db3d172015-06-02 15:58:43 -070077
Chris Craik1b54fb22015-06-02 17:40:58 -070078namespace FrameInfoFlags {
John Reck1bcacfd2017-11-03 10:12:19 -070079enum {
Jorim Jaggi95166052021-05-03 15:49:25 +020080 WindowVisibilityChanged = 1 << 0,
John Reck1bcacfd2017-11-03 10:12:19 -070081 RTAnimation = 1 << 1,
82 SurfaceCanvas = 1 << 2,
83 SkippedFrame = 1 << 3,
84};
John Reckc87be992015-02-20 10:57:22 -080085};
John Reckba6adf62015-02-19 14:36:50 -080086
Siarhei Vishniakouaed22822025-02-18 11:35:58 -080087using FrameInfoBuffer = std::array<int64_t, static_cast<size_t>(FrameInfoIndex::NumIndexes)>;
88
Derek Sollenberger3fedf5a2020-02-21 13:07:28 -050089class UiFrameInfoBuilder {
John Reckba6adf62015-02-19 14:36:50 -080090public:
Steven Thomas6fabb5a2020-08-21 16:56:08 -070091 static constexpr int64_t INVALID_VSYNC_ID = -1;
Jorim Jaggi10f328c2021-01-19 00:08:02 +010092 static constexpr int64_t UNKNOWN_DEADLINE = std::numeric_limits<int64_t>::max();
93 static constexpr int64_t UNKNOWN_FRAME_INTERVAL = -1;
94
Steven Thomas6fabb5a2020-08-21 16:56:08 -070095
Chih-Hung Hsiehfaecb782016-07-21 11:23:06 -070096 explicit UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) {
John Reckba6adf62015-02-19 14:36:50 -080097 memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
Steven Thomas6fabb5a2020-08-21 16:56:08 -070098 set(FrameInfoIndex::FrameTimelineVsyncId) = INVALID_VSYNC_ID;
Siarhei Vishniakoudca19462021-02-27 08:38:31 +000099 // The struct is zeroed by memset above. That also sets FrameInfoIndex::InputEventId to
100 // equal android::os::IInputConstants::INVALID_INPUT_EVENT_ID == 0.
101 // Therefore, we can skip setting the value for InputEventId here. If the value for
102 // INVALID_INPUT_EVENT_ID changes, this code would have to be updated, as well.
Ady Abrahamdfb13982020-10-05 17:59:09 -0700103 set(FrameInfoIndex::FrameDeadline) = std::numeric_limits<int64_t>::max();
John Reckba6adf62015-02-19 14:36:50 -0800104 }
105
Ady Abrahamdfb13982020-10-05 17:59:09 -0700106 UiFrameInfoBuilder& setVsync(nsecs_t vsyncTime, nsecs_t intendedVsync,
Jorim Jaggi10f328c2021-01-19 00:08:02 +0100107 int64_t vsyncId, int64_t frameDeadline, nsecs_t frameInterval) {
Steven Thomas6fabb5a2020-08-21 16:56:08 -0700108 set(FrameInfoIndex::FrameTimelineVsyncId) = vsyncId;
Chris Craik1b54fb22015-06-02 17:40:58 -0700109 set(FrameInfoIndex::Vsync) = vsyncTime;
110 set(FrameInfoIndex::IntendedVsync) = intendedVsync;
John Reckbf3c6022015-06-02 15:55:00 -0700111 // Pretend the other fields are all at vsync, too, so that naive
112 // duration calculations end up being 0 instead of very large
Chris Craik1b54fb22015-06-02 17:40:58 -0700113 set(FrameInfoIndex::HandleInputStart) = vsyncTime;
114 set(FrameInfoIndex::AnimationStart) = vsyncTime;
115 set(FrameInfoIndex::PerformTraversalsStart) = vsyncTime;
116 set(FrameInfoIndex::DrawStart) = vsyncTime;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000117 set(FrameInfoIndex::FrameStartTime) = vsyncTime;
Ady Abrahamdfb13982020-10-05 17:59:09 -0700118 set(FrameInfoIndex::FrameDeadline) = frameDeadline;
Jorim Jaggi10f328c2021-01-19 00:08:02 +0100119 set(FrameInfoIndex::FrameInterval) = frameInterval;
Melody Hsu92b519b2025-02-05 22:01:40 +0000120 set(FrameInfoIndex::WorkloadTarget) = frameDeadline - intendedVsync;
John Reckba6adf62015-02-19 14:36:50 -0800121 return *this;
122 }
123
Chris Craik1b54fb22015-06-02 17:40:58 -0700124 UiFrameInfoBuilder& addFlag(int frameInfoFlag) {
125 set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
John Reckba6adf62015-02-19 14:36:50 -0800126 return *this;
127 }
128
129private:
John Reck1bcacfd2017-11-03 10:12:19 -0700130 inline int64_t& set(FrameInfoIndex index) { return mBuffer[static_cast<int>(index)]; }
John Reckc87be992015-02-20 10:57:22 -0800131
John Reckba6adf62015-02-19 14:36:50 -0800132 int64_t* mBuffer;
133};
134
135class FrameInfo {
136public:
Siarhei Vishniakoub07fe1d2025-02-13 13:23:53 -0800137 void importUiThreadInfo(const int64_t* info);
John Reckba6adf62015-02-19 14:36:50 -0800138
Jerome Gaillarde218c692019-06-14 12:58:57 +0100139 void markSyncStart() { set(FrameInfoIndex::SyncStart) = systemTime(SYSTEM_TIME_MONOTONIC); }
John Reckba6adf62015-02-19 14:36:50 -0800140
141 void markIssueDrawCommandsStart() {
Jerome Gaillarde218c692019-06-14 12:58:57 +0100142 set(FrameInfoIndex::IssueDrawCommandsStart) = systemTime(SYSTEM_TIME_MONOTONIC);
John Reckba6adf62015-02-19 14:36:50 -0800143 }
144
Jerome Gaillarde218c692019-06-14 12:58:57 +0100145 void markSwapBuffers() { set(FrameInfoIndex::SwapBuffers) = systemTime(SYSTEM_TIME_MONOTONIC); }
John Reckba6adf62015-02-19 14:36:50 -0800146
Jorim Jaggi71db8892021-02-03 23:19:29 +0100147 void markSwapBuffersCompleted() {
148 set(FrameInfoIndex::SwapBuffersCompleted) = systemTime(SYSTEM_TIME_MONOTONIC);
149 }
150
Jerome Gaillarde218c692019-06-14 12:58:57 +0100151 void markFrameCompleted() { set(FrameInfoIndex::FrameCompleted) = systemTime(SYSTEM_TIME_MONOTONIC); }
John Reckba6adf62015-02-19 14:36:50 -0800152
Chris Craik1b54fb22015-06-02 17:40:58 -0700153 void addFlag(int frameInfoFlag) {
154 set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
John Reck240ff622015-04-28 13:50:00 -0700155 }
156
Siarhei Vishniakouaed22822025-02-18 11:35:58 -0800157 const FrameInfoBuffer& data() const { return mFrameInfo; }
Andres Morales06f5bc72015-12-15 15:21:31 -0800158
John Reck1bcacfd2017-11-03 10:12:19 -0700159 inline int64_t operator[](FrameInfoIndex index) const { return get(index); }
John Reckba6adf62015-02-19 14:36:50 -0800160
John Reck41300272015-06-03 14:42:34 -0700161 inline int64_t operator[](int index) const {
Chris Craik1b54fb22015-06-02 17:40:58 -0700162 if (index < 0 || index >= static_cast<int>(FrameInfoIndex::NumIndexes)) return 0;
John Reckc87be992015-02-20 10:57:22 -0800163 return mFrameInfo[index];
John Reckba6adf62015-02-19 14:36:50 -0800164 }
165
John Reck41300272015-06-03 14:42:34 -0700166 inline int64_t duration(FrameInfoIndex start, FrameInfoIndex end) const {
John Reckbe3fba02015-07-06 13:49:58 -0700167 int64_t endtime = get(end);
168 int64_t starttime = get(start);
John Reck41300272015-06-03 14:42:34 -0700169 int64_t gap = endtime - starttime;
170 gap = starttime > 0 ? gap : 0;
John Reck1bcacfd2017-11-03 10:12:19 -0700171 if (end > FrameInfoIndex::SyncQueued && start < FrameInfoIndex::SyncQueued) {
John Reckbe3fba02015-07-06 13:49:58 -0700172 // Need to subtract out the time spent in a stalled state
173 // as this will be captured by the previous frame's info
John Reck1bcacfd2017-11-03 10:12:19 -0700174 int64_t offset = get(FrameInfoIndex::SyncStart) - get(FrameInfoIndex::SyncQueued);
John Reckbe3fba02015-07-06 13:49:58 -0700175 if (offset > 0) {
176 gap -= offset;
177 }
178 }
John Reck41300272015-06-03 14:42:34 -0700179 return gap > 0 ? gap : 0;
180 }
181
182 inline int64_t totalDuration() const {
183 return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted);
184 }
185
Stan Iliev7203e1f2019-07-25 13:12:02 -0400186 inline int64_t gpuDrawTime() const {
187 // GPU start time is approximated to the moment before swapBuffer is invoked.
188 // We could add an EGLSyncKHR fence at the beginning of the frame, but that is an overhead.
189 int64_t endTime = get(FrameInfoIndex::GpuCompleted);
Boleyn Sua9ce6622020-11-18 03:15:29 +0000190 return endTime > 0 ? endTime - get(FrameInfoIndex::SwapBuffers) : -1;
Stan Iliev7203e1f2019-07-25 13:12:02 -0400191 }
192
John Reck1bcacfd2017-11-03 10:12:19 -0700193 inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; }
John Reckc87be992015-02-20 10:57:22 -0800194
John Reckbe3fba02015-07-06 13:49:58 -0700195 inline int64_t get(FrameInfoIndex index) const {
196 if (index == FrameInfoIndex::NumIndexes) return 0;
197 return mFrameInfo[static_cast<int>(index)];
198 }
199
Ady Abrahame088dcd2023-08-10 11:45:58 -0700200 void setSkippedFrameReason(SkippedFrameReason reason);
201 inline std::optional<SkippedFrameReason> getSkippedFrameReason() const {
202 return mSkippedFrameReason;
203 }
204
John Reckbe3fba02015-07-06 13:49:58 -0700205private:
Siarhei Vishniakouaed22822025-02-18 11:35:58 -0800206 FrameInfoBuffer mFrameInfo;
Ady Abrahame088dcd2023-08-10 11:45:58 -0700207 std::optional<SkippedFrameReason> mSkippedFrameReason;
John Reckba6adf62015-02-19 14:36:50 -0800208};
209
210} /* namespace uirenderer */
211} /* namespace android */
212
213#endif /* FRAMEINFO_H_ */