FrameInfo.h revision 65ddb154c75126bbef8bf03494e6fd0d98ee0127
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
27namespace android {
28namespace uirenderer {
29
30#define UI_THREAD_FRAME_INFO_SIZE 9
31
32enum 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
59extern const std::string FrameInfoNames[];
60
61namespace FrameInfoFlags {
62    enum {
63        WindowLayoutChanged = 1 << 0,
64        RTAnimation = 1 << 1,
65        SurfaceCanvas = 1 << 2,
66        SkippedFrame = 1 << 3,
67    };
68};
69
70class ANDROID_API UiFrameInfoBuilder {
71public:
72    UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) {
73        memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
74    }
75
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
88    UiFrameInfoBuilder& addFlag(int frameInfoFlag) {
89        set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
90        return *this;
91    }
92
93private:
94    inline int64_t& set(FrameInfoIndex index) {
95        return mBuffer[static_cast<int>(index)];
96    }
97
98    int64_t* mBuffer;
99};
100
101class FrameInfo {
102public:
103    void importUiThreadInfo(int64_t* info);
104
105    void markSyncStart() {
106        set(FrameInfoIndex::SyncStart) = systemTime(CLOCK_MONOTONIC);
107    }
108
109    void markIssueDrawCommandsStart() {
110        set(FrameInfoIndex::IssueDrawCommandsStart) = systemTime(CLOCK_MONOTONIC);
111    }
112
113    void markSwapBuffers() {
114        set(FrameInfoIndex::SwapBuffers) = systemTime(CLOCK_MONOTONIC);
115    }
116
117    void markFrameCompleted() {
118        set(FrameInfoIndex::FrameCompleted) = systemTime(CLOCK_MONOTONIC);
119    }
120
121    void addFlag(int frameInfoFlag) {
122        set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
123    }
124
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
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
156    inline int64_t totalDuration() const {
157        return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted);
158    }
159
160    inline int64_t& set(FrameInfoIndex index) {
161        return mFrameInfo[static_cast<int>(index)];
162    }
163
164    inline int64_t get(FrameInfoIndex index) const {
165        if (index == FrameInfoIndex::NumIndexes) return 0;
166        return mFrameInfo[static_cast<int>(index)];
167    }
168
169private:
170    int64_t mFrameInfo[static_cast<int>(FrameInfoIndex::NumIndexes)];
171};
172
173} /* namespace uirenderer */
174} /* namespace android */
175
176#endif /* FRAMEINFO_H_ */
177