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