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 <memory.h> 25 #include <string> 26 27 namespace android { 28 namespace uirenderer { 29 30 #define UI_THREAD_FRAME_INFO_SIZE 9 31 32 enum class FrameInfoIndex { 33 Flags = 0, 34 IntendedVsync, 35 Vsync, 36 OldestInputEvent, 37 NewestInputEvent, 38 HandleInputStart, 39 AnimationStart, 40 PerformTraversalsStart, 41 DrawStart, 42 // End of UI frame info 43 44 SyncQueued, 45 46 SyncStart, 47 IssueDrawCommandsStart, 48 SwapBuffers, 49 FrameCompleted, 50 51 DequeueBufferDuration, 52 QueueBufferDuration, 53 54 // Must be the last value! 55 // Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT 56 NumIndexes 57 }; 58 59 extern const std::string FrameInfoNames[]; 60 61 namespace FrameInfoFlags { 62 enum { 63 WindowLayoutChanged = 1 << 0, 64 RTAnimation = 1 << 1, 65 SurfaceCanvas = 1 << 2, 66 SkippedFrame = 1 << 3, 67 }; 68 }; 69 70 class ANDROID_API UiFrameInfoBuilder { 71 public: UiFrameInfoBuilder(int64_t * buffer)72 explicit UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) { 73 memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t)); 74 } 75 setVsync(nsecs_t vsyncTime,nsecs_t intendedVsync)76 UiFrameInfoBuilder& setVsync(nsecs_t vsyncTime, nsecs_t intendedVsync) { 77 set(FrameInfoIndex::Vsync) = vsyncTime; 78 set(FrameInfoIndex::IntendedVsync) = intendedVsync; 79 // Pretend the other fields are all at vsync, too, so that naive 80 // duration calculations end up being 0 instead of very large 81 set(FrameInfoIndex::HandleInputStart) = vsyncTime; 82 set(FrameInfoIndex::AnimationStart) = vsyncTime; 83 set(FrameInfoIndex::PerformTraversalsStart) = vsyncTime; 84 set(FrameInfoIndex::DrawStart) = vsyncTime; 85 return *this; 86 } 87 addFlag(int frameInfoFlag)88 UiFrameInfoBuilder& addFlag(int frameInfoFlag) { 89 set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag); 90 return *this; 91 } 92 93 private: set(FrameInfoIndex index)94 inline int64_t& set(FrameInfoIndex index) { 95 return mBuffer[static_cast<int>(index)]; 96 } 97 98 int64_t* mBuffer; 99 }; 100 101 class FrameInfo { 102 public: 103 void importUiThreadInfo(int64_t* info); 104 markSyncStart()105 void markSyncStart() { 106 set(FrameInfoIndex::SyncStart) = systemTime(CLOCK_MONOTONIC); 107 } 108 markIssueDrawCommandsStart()109 void markIssueDrawCommandsStart() { 110 set(FrameInfoIndex::IssueDrawCommandsStart) = systemTime(CLOCK_MONOTONIC); 111 } 112 markSwapBuffers()113 void markSwapBuffers() { 114 set(FrameInfoIndex::SwapBuffers) = systemTime(CLOCK_MONOTONIC); 115 } 116 markFrameCompleted()117 void markFrameCompleted() { 118 set(FrameInfoIndex::FrameCompleted) = systemTime(CLOCK_MONOTONIC); 119 } 120 addFlag(int frameInfoFlag)121 void addFlag(int frameInfoFlag) { 122 set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag); 123 } 124 data()125 const int64_t* data() const { 126 return mFrameInfo; 127 } 128 129 inline int64_t operator[](FrameInfoIndex index) const { 130 return get(index); 131 } 132 133 inline int64_t operator[](int index) const { 134 if (index < 0 || index >= static_cast<int>(FrameInfoIndex::NumIndexes)) return 0; 135 return mFrameInfo[index]; 136 } 137 duration(FrameInfoIndex start,FrameInfoIndex end)138 inline int64_t duration(FrameInfoIndex start, FrameInfoIndex end) const { 139 int64_t endtime = get(end); 140 int64_t starttime = get(start); 141 int64_t gap = endtime - starttime; 142 gap = starttime > 0 ? gap : 0; 143 if (end > FrameInfoIndex::SyncQueued && 144 start < FrameInfoIndex::SyncQueued) { 145 // Need to subtract out the time spent in a stalled state 146 // as this will be captured by the previous frame's info 147 int64_t offset = get(FrameInfoIndex::SyncStart) 148 - get(FrameInfoIndex::SyncQueued); 149 if (offset > 0) { 150 gap -= offset; 151 } 152 } 153 return gap > 0 ? gap : 0; 154 } 155 totalDuration()156 inline int64_t totalDuration() const { 157 return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted); 158 } 159 set(FrameInfoIndex index)160 inline int64_t& set(FrameInfoIndex index) { 161 return mFrameInfo[static_cast<int>(index)]; 162 } 163 get(FrameInfoIndex index)164 inline int64_t get(FrameInfoIndex index) const { 165 if (index == FrameInfoIndex::NumIndexes) return 0; 166 return mFrameInfo[static_cast<int>(index)]; 167 } 168 169 private: 170 int64_t mFrameInfo[static_cast<int>(FrameInfoIndex::NumIndexes)]; 171 }; 172 173 } /* namespace uirenderer */ 174 } /* namespace android */ 175 176 #endif /* FRAMEINFO_H_ */ 177