• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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  */
17 
18 #include <android/choreographer.h>
19 #include <android/log.h>
20 #include <android/looper.h>
21 #include <android/trace.h>
22 #include <jni.h>
23 #include <jniAssert.h>
24 #include <sys/time.h>
25 #include <time.h>
26 
27 #include <chrono>
28 #include <cinttypes>
29 #include <cmath>
30 #include <cstdlib>
31 #include <cstring>
32 #include <limits>
33 #include <mutex>
34 #include <set>
35 #include <sstream>
36 #include <string>
37 #include <thread>
38 #include <tuple>
39 #include <vector>
40 
41 using namespace std::chrono_literals;
42 static constexpr std::chrono::nanoseconds NOMINAL_VSYNC_PERIOD{16ms};
43 static constexpr std::chrono::nanoseconds DELAY_PERIOD{NOMINAL_VSYNC_PERIOD * 5};
44 static constexpr std::chrono::nanoseconds ZERO{std::chrono::nanoseconds::zero()};
45 
46 #define NANOS_PER_SECOND 1000000000LL
systemTime()47 static int64_t systemTime() {
48     struct timespec time;
49     int result = clock_gettime(CLOCK_MONOTONIC, &time);
50     if (result < 0) {
51         return -errno;
52     }
53     return (time.tv_sec * NANOS_PER_SECOND) + time.tv_nsec;
54 }
55 
56 static std::mutex gLock;
57 struct Callback {
CallbackCallback58     Callback(const char* name) : name(name) {}
59     std::string name;
60     int count{0};
61     std::chrono::nanoseconds frameTime{0LL};
62 };
63 
64 struct VsyncCallback : Callback {
VsyncCallbackVsyncCallback65     VsyncCallback(const char* name, JNIEnv* env) : Callback(name), env(env) {}
66 
67     struct FrameTime {
FrameTimeVsyncCallback::FrameTime68         FrameTime(const AChoreographerFrameCallbackData* callbackData, int index)
69               : vsyncId(AChoreographerFrameCallbackData_getFrameTimelineVsyncId(callbackData,
70                                                                                 index)),
71                 expectedPresentTime(
72                         AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos(
73                                 callbackData, index)),
74                 deadline(AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos(callbackData,
75                                                                                        index)) {}
76 
77         const AVsyncId vsyncId{-1};
78         const int64_t expectedPresentTime{-1};
79         const int64_t deadline{-1};
80     };
81 
populateVsyncCallback82     void populate(const AChoreographerFrameCallbackData* callbackData) {
83         size_t index = AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(callbackData);
84         preferredFrameTimelineIndex = index;
85 
86         size_t length = AChoreographerFrameCallbackData_getFrameTimelinesLength(callbackData);
87         {
88             std::lock_guard<std::mutex> _l{gLock};
89             ASSERT(length >= 1, "Frame timelines should not be empty");
90             ASSERT(index < length, "Frame timeline index must be less than length");
91         }
92         timeline.reserve(length);
93 
94         for (int i = 0; i < length; i++) {
95             timeline.push_back(FrameTime(callbackData, i));
96         }
97     }
98 
getPreferredFrameTimelineIndexVsyncCallback99     size_t getPreferredFrameTimelineIndex() const { return preferredFrameTimelineIndex; }
getTimelineVsyncCallback100     const std::vector<FrameTime>& getTimeline() const { return timeline; }
101 
102 private:
103     JNIEnv* env;
104     size_t preferredFrameTimelineIndex{std::numeric_limits<size_t>::max()};
105     std::vector<FrameTime> timeline;
106 };
107 
vsyncCallback(int64_t frameTimeNanos,void * data)108 static void vsyncCallback(int64_t frameTimeNanos, void* data) {
109     std::lock_guard<std::mutex> _l(gLock);
110     ATrace_beginSection("vsyncCallback base");
111     Callback* cb = static_cast<Callback*>(data);
112     cb->count++;
113     cb->frameTime = std::chrono::nanoseconds{frameTimeNanos};
114     ATrace_endSection();
115 }
116 
vsyncCallback(const AChoreographerFrameCallbackData * callbackData,void * data)117 static void vsyncCallback(const AChoreographerFrameCallbackData* callbackData, void* data) {
118     ATrace_beginSection("vsyncCallback");
119     vsyncCallback(AChoreographerFrameCallbackData_getFrameTimeNanos(callbackData), data);
120 
121     VsyncCallback* cb = static_cast<VsyncCallback*>(data);
122     cb->populate(callbackData);
123     ATrace_endSection();
124 }
125 
frameCallback64(int64_t frameTimeNanos,void * data)126 static void frameCallback64(int64_t frameTimeNanos, void* data) {
127     vsyncCallback(frameTimeNanos, data);
128 }
129 
frameCallback(long frameTimeNanos,void * data)130 static void frameCallback(long frameTimeNanos, void* data) {
131     vsyncCallback((int64_t)frameTimeNanos, data);
132 }
133 
now()134 static std::chrono::nanoseconds now() {
135     return std::chrono::steady_clock::now().time_since_epoch();
136 }
137 
verifyCallback(JNIEnv * env,const Callback & cb,int expectedCount,std::chrono::nanoseconds startTime,std::chrono::nanoseconds maxTime)138 static void verifyCallback(JNIEnv* env, const Callback& cb, int expectedCount,
139                            std::chrono::nanoseconds startTime, std::chrono::nanoseconds maxTime) {
140     std::lock_guard<std::mutex> _l{gLock};
141     ASSERT(cb.count == expectedCount, "Choreographer failed to invoke '%s' %d times - actual: %d",
142            cb.name.c_str(), expectedCount, cb.count);
143     if (maxTime > ZERO) {
144         auto duration = cb.frameTime - startTime;
145         ASSERT(duration < maxTime, "Callback '%s' has incorrect frame time in invocation %d",
146                cb.name.c_str(), expectedCount);
147     }
148 }
149