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