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