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 static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 12; 34 35 enum class FrameInfoIndex { 36 Flags = 0, 37 FrameTimelineVsyncId, 38 IntendedVsync, 39 Vsync, 40 InputEventId, 41 HandleInputStart, 42 AnimationStart, 43 PerformTraversalsStart, 44 DrawStart, 45 FrameDeadline, 46 FrameStartTime, 47 FrameInterval, 48 // End of UI frame info 49 50 SyncQueued, 51 52 SyncStart, 53 IssueDrawCommandsStart, 54 SwapBuffers, 55 FrameCompleted, 56 57 DequeueBufferDuration, 58 QueueBufferDuration, 59 60 GpuCompleted, 61 SwapBuffersCompleted, 62 DisplayPresentTime, 63 CommandSubmissionCompleted, 64 65 // Must be the last value! 66 // Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT 67 NumIndexes 68 }; 69 70 extern const std::array<const char*, static_cast<int>(FrameInfoIndex::NumIndexes)> FrameInfoNames; 71 72 namespace FrameInfoFlags { 73 enum { 74 WindowVisibilityChanged = 1 << 0, 75 RTAnimation = 1 << 1, 76 SurfaceCanvas = 1 << 2, 77 SkippedFrame = 1 << 3, 78 }; 79 }; 80 81 class UiFrameInfoBuilder { 82 public: 83 static constexpr int64_t INVALID_VSYNC_ID = -1; 84 static constexpr int64_t UNKNOWN_DEADLINE = std::numeric_limits<int64_t>::max(); 85 static constexpr int64_t UNKNOWN_FRAME_INTERVAL = -1; 86 87 UiFrameInfoBuilder(int64_t * buffer)88 explicit UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) { 89 memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t)); 90 set(FrameInfoIndex::FrameTimelineVsyncId) = INVALID_VSYNC_ID; 91 // The struct is zeroed by memset above. That also sets FrameInfoIndex::InputEventId to 92 // equal android::os::IInputConstants::INVALID_INPUT_EVENT_ID == 0. 93 // Therefore, we can skip setting the value for InputEventId here. If the value for 94 // INVALID_INPUT_EVENT_ID changes, this code would have to be updated, as well. 95 set(FrameInfoIndex::FrameDeadline) = std::numeric_limits<int64_t>::max(); 96 } 97 setVsync(nsecs_t vsyncTime,nsecs_t intendedVsync,int64_t vsyncId,int64_t frameDeadline,nsecs_t frameInterval)98 UiFrameInfoBuilder& setVsync(nsecs_t vsyncTime, nsecs_t intendedVsync, 99 int64_t vsyncId, int64_t frameDeadline, nsecs_t frameInterval) { 100 set(FrameInfoIndex::FrameTimelineVsyncId) = vsyncId; 101 set(FrameInfoIndex::Vsync) = vsyncTime; 102 set(FrameInfoIndex::IntendedVsync) = intendedVsync; 103 // Pretend the other fields are all at vsync, too, so that naive 104 // duration calculations end up being 0 instead of very large 105 set(FrameInfoIndex::HandleInputStart) = vsyncTime; 106 set(FrameInfoIndex::AnimationStart) = vsyncTime; 107 set(FrameInfoIndex::PerformTraversalsStart) = vsyncTime; 108 set(FrameInfoIndex::DrawStart) = vsyncTime; 109 set(FrameInfoIndex::FrameStartTime) = vsyncTime; 110 set(FrameInfoIndex::FrameDeadline) = frameDeadline; 111 set(FrameInfoIndex::FrameInterval) = frameInterval; 112 return *this; 113 } 114 addFlag(int frameInfoFlag)115 UiFrameInfoBuilder& addFlag(int frameInfoFlag) { 116 set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag); 117 return *this; 118 } 119 120 private: set(FrameInfoIndex index)121 inline int64_t& set(FrameInfoIndex index) { return mBuffer[static_cast<int>(index)]; } 122 123 int64_t* mBuffer; 124 }; 125 126 class FrameInfo { 127 public: 128 void importUiThreadInfo(int64_t* info); 129 markSyncStart()130 void markSyncStart() { set(FrameInfoIndex::SyncStart) = systemTime(SYSTEM_TIME_MONOTONIC); } 131 markIssueDrawCommandsStart()132 void markIssueDrawCommandsStart() { 133 set(FrameInfoIndex::IssueDrawCommandsStart) = systemTime(SYSTEM_TIME_MONOTONIC); 134 } 135 markSwapBuffers()136 void markSwapBuffers() { set(FrameInfoIndex::SwapBuffers) = systemTime(SYSTEM_TIME_MONOTONIC); } 137 markSwapBuffersCompleted()138 void markSwapBuffersCompleted() { 139 set(FrameInfoIndex::SwapBuffersCompleted) = systemTime(SYSTEM_TIME_MONOTONIC); 140 } 141 markFrameCompleted()142 void markFrameCompleted() { set(FrameInfoIndex::FrameCompleted) = systemTime(SYSTEM_TIME_MONOTONIC); } 143 addFlag(int frameInfoFlag)144 void addFlag(int frameInfoFlag) { 145 set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag); 146 } 147 data()148 const int64_t* data() const { return mFrameInfo; } 149 150 inline int64_t operator[](FrameInfoIndex index) const { return get(index); } 151 152 inline int64_t operator[](int index) const { 153 if (index < 0 || index >= static_cast<int>(FrameInfoIndex::NumIndexes)) return 0; 154 return mFrameInfo[index]; 155 } 156 duration(FrameInfoIndex start,FrameInfoIndex end)157 inline int64_t duration(FrameInfoIndex start, FrameInfoIndex end) const { 158 int64_t endtime = get(end); 159 int64_t starttime = get(start); 160 int64_t gap = endtime - starttime; 161 gap = starttime > 0 ? gap : 0; 162 if (end > FrameInfoIndex::SyncQueued && start < FrameInfoIndex::SyncQueued) { 163 // Need to subtract out the time spent in a stalled state 164 // as this will be captured by the previous frame's info 165 int64_t offset = get(FrameInfoIndex::SyncStart) - get(FrameInfoIndex::SyncQueued); 166 if (offset > 0) { 167 gap -= offset; 168 } 169 } 170 return gap > 0 ? gap : 0; 171 } 172 totalDuration()173 inline int64_t totalDuration() const { 174 return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted); 175 } 176 gpuDrawTime()177 inline int64_t gpuDrawTime() const { 178 // GPU start time is approximated to the moment before swapBuffer is invoked. 179 // We could add an EGLSyncKHR fence at the beginning of the frame, but that is an overhead. 180 int64_t endTime = get(FrameInfoIndex::GpuCompleted); 181 return endTime > 0 ? endTime - get(FrameInfoIndex::SwapBuffers) : -1; 182 } 183 set(FrameInfoIndex index)184 inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; } 185 get(FrameInfoIndex index)186 inline int64_t get(FrameInfoIndex index) const { 187 if (index == FrameInfoIndex::NumIndexes) return 0; 188 return mFrameInfo[static_cast<int>(index)]; 189 } 190 191 void setSkippedFrameReason(SkippedFrameReason reason); getSkippedFrameReason()192 inline std::optional<SkippedFrameReason> getSkippedFrameReason() const { 193 return mSkippedFrameReason; 194 } 195 196 private: 197 int64_t mFrameInfo[static_cast<int>(FrameInfoIndex::NumIndexes)]; 198 std::optional<SkippedFrameReason> mSkippedFrameReason; 199 }; 200 201 } /* namespace uirenderer */ 202 } /* namespace android */ 203 204 #endif /* FRAMEINFO_H_ */ 205