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 GpuCompleted, 55 56 // Must be the last value! 57 // Also must be kept in sync with FrameMetrics.java#FRAME_STATS_COUNT 58 NumIndexes 59 }; 60 61 extern const std::string FrameInfoNames[]; 62 63 namespace FrameInfoFlags { 64 enum { 65 WindowLayoutChanged = 1 << 0, 66 RTAnimation = 1 << 1, 67 SurfaceCanvas = 1 << 2, 68 SkippedFrame = 1 << 3, 69 }; 70 }; 71 72 class ANDROID_API UiFrameInfoBuilder { 73 public: UiFrameInfoBuilder(int64_t * buffer)74 explicit UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) { 75 memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t)); 76 } 77 setVsync(nsecs_t vsyncTime,nsecs_t intendedVsync)78 UiFrameInfoBuilder& setVsync(nsecs_t vsyncTime, nsecs_t intendedVsync) { 79 set(FrameInfoIndex::Vsync) = vsyncTime; 80 set(FrameInfoIndex::IntendedVsync) = intendedVsync; 81 // Pretend the other fields are all at vsync, too, so that naive 82 // duration calculations end up being 0 instead of very large 83 set(FrameInfoIndex::HandleInputStart) = vsyncTime; 84 set(FrameInfoIndex::AnimationStart) = vsyncTime; 85 set(FrameInfoIndex::PerformTraversalsStart) = vsyncTime; 86 set(FrameInfoIndex::DrawStart) = vsyncTime; 87 return *this; 88 } 89 addFlag(int frameInfoFlag)90 UiFrameInfoBuilder& addFlag(int frameInfoFlag) { 91 set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag); 92 return *this; 93 } 94 95 private: set(FrameInfoIndex index)96 inline int64_t& set(FrameInfoIndex index) { return mBuffer[static_cast<int>(index)]; } 97 98 int64_t* mBuffer; 99 }; 100 101 class FrameInfo { 102 public: 103 void importUiThreadInfo(int64_t* info); 104 markSyncStart()105 void markSyncStart() { set(FrameInfoIndex::SyncStart) = systemTime(SYSTEM_TIME_MONOTONIC); } 106 markIssueDrawCommandsStart()107 void markIssueDrawCommandsStart() { 108 set(FrameInfoIndex::IssueDrawCommandsStart) = systemTime(SYSTEM_TIME_MONOTONIC); 109 } 110 markSwapBuffers()111 void markSwapBuffers() { set(FrameInfoIndex::SwapBuffers) = systemTime(SYSTEM_TIME_MONOTONIC); } 112 markFrameCompleted()113 void markFrameCompleted() { set(FrameInfoIndex::FrameCompleted) = systemTime(SYSTEM_TIME_MONOTONIC); } 114 addFlag(int frameInfoFlag)115 void addFlag(int frameInfoFlag) { 116 set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag); 117 } 118 data()119 const int64_t* data() const { return mFrameInfo; } 120 121 inline int64_t operator[](FrameInfoIndex index) const { return get(index); } 122 123 inline int64_t operator[](int index) const { 124 if (index < 0 || index >= static_cast<int>(FrameInfoIndex::NumIndexes)) return 0; 125 return mFrameInfo[index]; 126 } 127 duration(FrameInfoIndex start,FrameInfoIndex end)128 inline int64_t duration(FrameInfoIndex start, FrameInfoIndex end) const { 129 int64_t endtime = get(end); 130 int64_t starttime = get(start); 131 int64_t gap = endtime - starttime; 132 gap = starttime > 0 ? gap : 0; 133 if (end > FrameInfoIndex::SyncQueued && start < FrameInfoIndex::SyncQueued) { 134 // Need to subtract out the time spent in a stalled state 135 // as this will be captured by the previous frame's info 136 int64_t offset = get(FrameInfoIndex::SyncStart) - get(FrameInfoIndex::SyncQueued); 137 if (offset > 0) { 138 gap -= offset; 139 } 140 } 141 return gap > 0 ? gap : 0; 142 } 143 totalDuration()144 inline int64_t totalDuration() const { 145 return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted); 146 } 147 gpuDrawTime()148 inline int64_t gpuDrawTime() const { 149 // GPU start time is approximated to the moment before swapBuffer is invoked. 150 // We could add an EGLSyncKHR fence at the beginning of the frame, but that is an overhead. 151 int64_t endTime = get(FrameInfoIndex::GpuCompleted); 152 return endTime > 0 ? endTime - get(FrameInfoIndex::SwapBuffers) : -1; 153 } 154 set(FrameInfoIndex index)155 inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; } 156 get(FrameInfoIndex index)157 inline int64_t get(FrameInfoIndex index) const { 158 if (index == FrameInfoIndex::NumIndexes) return 0; 159 return mFrameInfo[static_cast<int>(index)]; 160 } 161 162 private: 163 int64_t mFrameInfo[static_cast<int>(FrameInfoIndex::NumIndexes)]; 164 }; 165 166 } /* namespace uirenderer */ 167 } /* namespace android */ 168 169 #endif /* FRAMEINFO_H_ */ 170