• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
19 #include <cutils/compiler.h>
20 #include <memory.h>
21 #include <utils/Timers.h>
22 
23 #include <array>
24 #include <optional>
25 #include <string>
26 
27 #include "SkippedFrameInfo.h"
28 #include "utils/Macros.h"
29 
30 namespace android {
31 namespace uirenderer {
32 
33 // This value must be in sync with `FRAME_INFO_SIZE` in FrameInfo.Java
34 static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 13;
35 
36 enum class FrameInfoIndex {
37     Flags = 0,
38     FrameTimelineVsyncId,
39     IntendedVsync,
40     Vsync,
41     InputEventId,
42     HandleInputStart,
43     AnimationStart,
44     PerformTraversalsStart,
45     DrawStart,
46     FrameDeadline,
47     FrameStartTime,
48     FrameInterval,
49     // End of UI frame info
50 
51     // 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 
56     SyncQueued,
57 
58     SyncStart,
59     IssueDrawCommandsStart,
60     SwapBuffers,
61     FrameCompleted,
62 
63     DequeueBufferDuration,
64     QueueBufferDuration,
65 
66     GpuCompleted,
67     SwapBuffersCompleted,
68     DisplayPresentTime,
69     CommandSubmissionCompleted,
70 
71     // Must be the last value!
72     // Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT
73     NumIndexes
74 };
75 
76 extern const std::array<const char*, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames;
77 
78 namespace FrameInfoFlags {
79 enum {
80     WindowVisibilityChanged = 1 << 0,
81     RTAnimation = 1 << 1,
82     SurfaceCanvas = 1 << 2,
83     SkippedFrame = 1 << 3,
84 };
85 };
86 
87 using FrameInfoBuffer = std::array<int64_t, static_cast<size_t>(FrameInfoIndex::NumIndexes)>;
88 
89 class UiFrameInfoBuilder {
90 public:
91     static constexpr int64_t INVALID_VSYNC_ID = -1;
92     static constexpr int64_t UNKNOWN_DEADLINE = std::numeric_limits<int64_t>::max();
93     static constexpr int64_t UNKNOWN_FRAME_INTERVAL = -1;
94 
95 
UiFrameInfoBuilder(int64_t * buffer)96     explicit UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) {
97         memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
98         set(FrameInfoIndex::FrameTimelineVsyncId) = INVALID_VSYNC_ID;
99         // 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.
103         set(FrameInfoIndex::FrameDeadline) = std::numeric_limits<int64_t>::max();
104     }
105 
setVsync(nsecs_t vsyncTime,nsecs_t intendedVsync,int64_t vsyncId,int64_t frameDeadline,nsecs_t frameInterval)106     UiFrameInfoBuilder& setVsync(nsecs_t vsyncTime, nsecs_t intendedVsync,
107                                  int64_t vsyncId, int64_t frameDeadline, nsecs_t frameInterval) {
108         set(FrameInfoIndex::FrameTimelineVsyncId) = vsyncId;
109         set(FrameInfoIndex::Vsync) = vsyncTime;
110         set(FrameInfoIndex::IntendedVsync) = intendedVsync;
111         // Pretend the other fields are all at vsync, too, so that naive
112         // duration calculations end up being 0 instead of very large
113         set(FrameInfoIndex::HandleInputStart) = vsyncTime;
114         set(FrameInfoIndex::AnimationStart) = vsyncTime;
115         set(FrameInfoIndex::PerformTraversalsStart) = vsyncTime;
116         set(FrameInfoIndex::DrawStart) = vsyncTime;
117         set(FrameInfoIndex::FrameStartTime) = vsyncTime;
118         set(FrameInfoIndex::FrameDeadline) = frameDeadline;
119         set(FrameInfoIndex::FrameInterval) = frameInterval;
120         set(FrameInfoIndex::WorkloadTarget) = frameDeadline - intendedVsync;
121         return *this;
122     }
123 
addFlag(int frameInfoFlag)124     UiFrameInfoBuilder& addFlag(int frameInfoFlag) {
125         set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
126         return *this;
127     }
128 
129 private:
set(FrameInfoIndex index)130     inline int64_t& set(FrameInfoIndex index) { return mBuffer[static_cast<int>(index)]; }
131 
132     int64_t* mBuffer;
133 };
134 
135 class FrameInfo {
136 public:
137     void importUiThreadInfo(const int64_t* info);
138 
markSyncStart()139     void markSyncStart() { set(FrameInfoIndex::SyncStart) = systemTime(SYSTEM_TIME_MONOTONIC); }
140 
markIssueDrawCommandsStart()141     void markIssueDrawCommandsStart() {
142         set(FrameInfoIndex::IssueDrawCommandsStart) = systemTime(SYSTEM_TIME_MONOTONIC);
143     }
144 
markSwapBuffers()145     void markSwapBuffers() { set(FrameInfoIndex::SwapBuffers) = systemTime(SYSTEM_TIME_MONOTONIC); }
146 
markSwapBuffersCompleted()147     void markSwapBuffersCompleted() {
148         set(FrameInfoIndex::SwapBuffersCompleted) = systemTime(SYSTEM_TIME_MONOTONIC);
149     }
150 
markFrameCompleted()151     void markFrameCompleted() { set(FrameInfoIndex::FrameCompleted) = systemTime(SYSTEM_TIME_MONOTONIC); }
152 
addFlag(int frameInfoFlag)153     void addFlag(int frameInfoFlag) {
154         set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
155     }
156 
data()157     const FrameInfoBuffer& data() const { return mFrameInfo; }
158 
159     inline int64_t operator[](FrameInfoIndex index) const { return get(index); }
160 
161     inline int64_t operator[](int index) const {
162         if (index < 0 || index >= static_cast<int>(FrameInfoIndex::NumIndexes)) return 0;
163         return mFrameInfo[index];
164     }
165 
duration(FrameInfoIndex start,FrameInfoIndex end)166     inline int64_t duration(FrameInfoIndex start, FrameInfoIndex end) const {
167         int64_t endtime = get(end);
168         int64_t starttime = get(start);
169         int64_t gap = endtime - starttime;
170         gap = starttime > 0 ? gap : 0;
171         if (end > FrameInfoIndex::SyncQueued && start < FrameInfoIndex::SyncQueued) {
172             // Need to subtract out the time spent in a stalled state
173             // as this will be captured by the previous frame's info
174             int64_t offset = get(FrameInfoIndex::SyncStart) - get(FrameInfoIndex::SyncQueued);
175             if (offset > 0) {
176                 gap -= offset;
177             }
178         }
179         return gap > 0 ? gap : 0;
180     }
181 
totalDuration()182     inline int64_t totalDuration() const {
183         return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted);
184     }
185 
gpuDrawTime()186     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);
190         return endTime > 0 ? endTime - get(FrameInfoIndex::SwapBuffers) : -1;
191     }
192 
set(FrameInfoIndex index)193     inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; }
194 
get(FrameInfoIndex index)195     inline int64_t get(FrameInfoIndex index) const {
196         if (index == FrameInfoIndex::NumIndexes) return 0;
197         return mFrameInfo[static_cast<int>(index)];
198     }
199 
200     void setSkippedFrameReason(SkippedFrameReason reason);
getSkippedFrameReason()201     inline std::optional<SkippedFrameReason> getSkippedFrameReason() const {
202         return mSkippedFrameReason;
203     }
204 
205 private:
206     FrameInfoBuffer mFrameInfo;
207     std::optional<SkippedFrameReason> mSkippedFrameReason;
208 };
209 
210 } /* namespace uirenderer */
211 } /* namespace android */
212 
213 #endif /* FRAMEINFO_H_ */
214