• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 #define LOG_TAG "Choreographer"
18 //#define LOG_NDEBUG 0
19 
20 #include <cinttypes>
21 #include <queue>
22 #include <thread>
23 
24 #include <android/choreographer.h>
25 #include <androidfw/DisplayEventDispatcher.h>
26 #include <gui/ISurfaceComposer.h>
27 #include <gui/SurfaceComposerClient.h>
28 #include <utils/Looper.h>
29 #include <utils/Mutex.h>
30 #include <utils/Timers.h>
31 
32 namespace android {
33 
toString(bool value)34 static inline const char* toString(bool value) {
35     return value ? "true" : "false";
36 }
37 
38 struct FrameCallback {
39     AChoreographer_frameCallback callback;
40     AChoreographer_frameCallback64 callback64;
41     void* data;
42     nsecs_t dueTime;
43 
operator <android::FrameCallback44     inline bool operator<(const FrameCallback& rhs) const {
45         // Note that this is intentionally flipped because we want callbacks due sooner to be at
46         // the head of the queue
47         return dueTime > rhs.dueTime;
48     }
49 };
50 
51 
52 class Choreographer : public DisplayEventDispatcher, public MessageHandler {
53 public:
54     void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
55                                   AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
56 
57     enum {
58         MSG_SCHEDULE_CALLBACKS = 0,
59         MSG_SCHEDULE_VSYNC = 1
60     };
61     virtual void handleMessage(const Message& message) override;
62 
63     static Choreographer* getForThread();
64 
65 protected:
66     virtual ~Choreographer() = default;
67 
68 private:
69     explicit Choreographer(const sp<Looper>& looper);
70     Choreographer(const Choreographer&) = delete;
71 
72     void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
73     void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
74     void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
75                                int32_t configId) override;
76 
77     void scheduleCallbacks();
78 
79     // Protected by mLock
80     std::priority_queue<FrameCallback> mCallbacks;
81 
82     mutable Mutex mLock;
83 
84     const sp<Looper> mLooper;
85     const std::thread::id mThreadId;
86 };
87 
88 
89 static thread_local Choreographer* gChoreographer;
getForThread()90 Choreographer* Choreographer::getForThread() {
91     if (gChoreographer == nullptr) {
92         sp<Looper> looper = Looper::getForThread();
93         if (!looper.get()) {
94             ALOGW("No looper prepared for thread");
95             return nullptr;
96         }
97         gChoreographer = new Choreographer(looper);
98         status_t result = gChoreographer->initialize();
99         if (result != OK) {
100             ALOGW("Failed to initialize");
101             return nullptr;
102         }
103     }
104     return gChoreographer;
105 }
106 
Choreographer(const sp<Looper> & looper)107 Choreographer::Choreographer(const sp<Looper>& looper) :
108     DisplayEventDispatcher(looper), mLooper(looper), mThreadId(std::this_thread::get_id()) {
109 }
110 
postFrameCallbackDelayed(AChoreographer_frameCallback cb,AChoreographer_frameCallback64 cb64,void * data,nsecs_t delay)111 void Choreographer::postFrameCallbackDelayed(
112         AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) {
113     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
114     FrameCallback callback{cb, cb64, data, now + delay};
115     {
116         AutoMutex _l{mLock};
117         mCallbacks.push(callback);
118     }
119     if (callback.dueTime <= now) {
120         if (std::this_thread::get_id() != mThreadId) {
121             Message m{MSG_SCHEDULE_VSYNC};
122             mLooper->sendMessage(this, m);
123         } else {
124             scheduleVsync();
125         }
126     } else {
127         Message m{MSG_SCHEDULE_CALLBACKS};
128         mLooper->sendMessageDelayed(delay, this, m);
129     }
130 }
131 
scheduleCallbacks()132 void Choreographer::scheduleCallbacks() {
133     AutoMutex _{mLock};
134     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
135     if (mCallbacks.top().dueTime <= now) {
136         ALOGV("choreographer %p ~ scheduling vsync", this);
137         scheduleVsync();
138         return;
139     }
140 }
141 
142 // TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
143 // internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
144 // the internal display implicitly.
dispatchVsync(nsecs_t timestamp,PhysicalDisplayId,uint32_t)145 void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) {
146     std::vector<FrameCallback> callbacks{};
147     {
148         AutoMutex _l{mLock};
149         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
150         while (!mCallbacks.empty() && mCallbacks.top().dueTime < now) {
151             callbacks.push_back(mCallbacks.top());
152             mCallbacks.pop();
153         }
154     }
155     for (const auto& cb : callbacks) {
156         if (cb.callback64 != nullptr) {
157             cb.callback64(timestamp, cb.data);
158         } else if (cb.callback != nullptr) {
159             cb.callback(timestamp, cb.data);
160         }
161     }
162 }
163 
dispatchHotplug(nsecs_t,PhysicalDisplayId displayId,bool connected)164 void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) {
165     ALOGV("choreographer %p ~ received hotplug event (displayId=%"
166             ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", connected=%s), ignoring.",
167             this, displayId, toString(connected));
168 }
169 
dispatchConfigChanged(nsecs_t,PhysicalDisplayId displayId,int32_t configId)170 void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId,
171                                           int32_t configId) {
172     ALOGV("choreographer %p ~ received config changed event (displayId=%"
173             ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%s), ignoring.",
174             this, displayId, toString(configId));
175 }
176 
handleMessage(const Message & message)177 void Choreographer::handleMessage(const Message& message) {
178     switch (message.what) {
179     case MSG_SCHEDULE_CALLBACKS:
180         scheduleCallbacks();
181         break;
182     case MSG_SCHEDULE_VSYNC:
183         scheduleVsync();
184         break;
185     }
186 }
187 
188 }
189 
190 /* Glue for the NDK interface */
191 
192 using android::Choreographer;
193 
AChoreographer_to_Choreographer(AChoreographer * choreographer)194 static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) {
195     return reinterpret_cast<Choreographer*>(choreographer);
196 }
197 
Choreographer_to_AChoreographer(Choreographer * choreographer)198 static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) {
199     return reinterpret_cast<AChoreographer*>(choreographer);
200 }
201 
AChoreographer_getInstance()202 AChoreographer* AChoreographer_getInstance() {
203     return Choreographer_to_AChoreographer(Choreographer::getForThread());
204 }
205 
AChoreographer_postFrameCallback(AChoreographer * choreographer,AChoreographer_frameCallback callback,void * data)206 void AChoreographer_postFrameCallback(AChoreographer* choreographer,
207         AChoreographer_frameCallback callback, void* data) {
208     AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
209             callback, nullptr, data, 0);
210 }
AChoreographer_postFrameCallbackDelayed(AChoreographer * choreographer,AChoreographer_frameCallback callback,void * data,long delayMillis)211 void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
212         AChoreographer_frameCallback callback, void* data, long delayMillis) {
213     AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
214             callback, nullptr, data, ms2ns(delayMillis));
215 }
AChoreographer_postFrameCallback64(AChoreographer * choreographer,AChoreographer_frameCallback64 callback,void * data)216 void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
217         AChoreographer_frameCallback64 callback, void* data) {
218     AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
219             nullptr, callback, data, 0);
220 }
AChoreographer_postFrameCallbackDelayed64(AChoreographer * choreographer,AChoreographer_frameCallback64 callback,void * data,uint32_t delayMillis)221 void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
222         AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) {
223     AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
224             nullptr, callback, data, ms2ns(delayMillis));
225 }
226