blob: 63e073405fe0cfa537bb7eea77f59ef477127636 [file] [log] [blame]
Michael Wright63c168a2015-12-04 17:59:42 +00001/*
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>
Dominik Laskowski3316a0a2019-01-25 02:56:41 -080027#include <gui/SurfaceComposerClient.h>
Michael Wright63c168a2015-12-04 17:59:42 +000028#include <utils/Looper.h>
29#include <utils/Mutex.h>
30#include <utils/Timers.h>
31
32namespace android {
33
34static inline const char* toString(bool value) {
35 return value ? "true" : "false";
36}
37
38struct FrameCallback {
39 AChoreographer_frameCallback callback;
Santos Cordon458d3df2019-02-20 18:09:00 +000040 AChoreographer_frameCallback64 callback64;
Michael Wright63c168a2015-12-04 17:59:42 +000041 void* data;
42 nsecs_t dueTime;
43
44 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
52class Choreographer : public DisplayEventDispatcher, public MessageHandler {
53public:
Santos Cordon458d3df2019-02-20 18:09:00 +000054 void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
55 AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
Michael Wright63c168a2015-12-04 17:59:42 +000056
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
65protected:
66 virtual ~Choreographer() = default;
67
68private:
Chih-Hung Hsiehc6baf562016-04-27 11:29:23 -070069 explicit Choreographer(const sp<Looper>& looper);
Michael Wright63c168a2015-12-04 17:59:42 +000070 Choreographer(const Choreographer&) = delete;
71
Dominik Laskowski3316a0a2019-01-25 02:56:41 -080072 void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
73 void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
Ady Abrahama5a21f72019-02-13 16:41:59 -080074 void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
75 int32_t configId) override;
Michael Wright63c168a2015-12-04 17:59:42 +000076
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
Michael Wrightc0d3d3f2016-01-26 16:03:25 -080089static thread_local Choreographer* gChoreographer;
Michael Wright63c168a2015-12-04 17:59:42 +000090Choreographer* 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
107Choreographer::Choreographer(const sp<Looper>& looper) :
108 DisplayEventDispatcher(looper), mLooper(looper), mThreadId(std::this_thread::get_id()) {
109}
110
Michael Wright63c168a2015-12-04 17:59:42 +0000111void Choreographer::postFrameCallbackDelayed(
Santos Cordon458d3df2019-02-20 18:09:00 +0000112 AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) {
Michael Wright63c168a2015-12-04 17:59:42 +0000113 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
Santos Cordon458d3df2019-02-20 18:09:00 +0000114 FrameCallback callback{cb, cb64, data, now + delay};
Michael Wright63c168a2015-12-04 17:59:42 +0000115 {
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
132void 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
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800142// 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.
145void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) {
Michael Wright63c168a2015-12-04 17:59:42 +0000146 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) {
Santos Cordon458d3df2019-02-20 18:09:00 +0000156 if (cb.callback64 != nullptr) {
157 cb.callback64(timestamp, cb.data);
158 } else if (cb.callback != nullptr) {
159 cb.callback(timestamp, cb.data);
160 }
Michael Wright63c168a2015-12-04 17:59:42 +0000161 }
162}
163
Dominik Laskowski3316a0a2019-01-25 02:56:41 -0800164void 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));
Michael Wright63c168a2015-12-04 17:59:42 +0000168}
169
Ady Abrahama5a21f72019-02-13 16:41:59 -0800170void 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
Michael Wright63c168a2015-12-04 17:59:42 +0000177void 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
192using android::Choreographer;
193
194static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) {
195 return reinterpret_cast<Choreographer*>(choreographer);
196}
197
198static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) {
199 return reinterpret_cast<AChoreographer*>(choreographer);
200}
201
202AChoreographer* AChoreographer_getInstance() {
203 return Choreographer_to_AChoreographer(Choreographer::getForThread());
204}
205
206void AChoreographer_postFrameCallback(AChoreographer* choreographer,
207 AChoreographer_frameCallback callback, void* data) {
Santos Cordon458d3df2019-02-20 18:09:00 +0000208 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
209 callback, nullptr, data, 0);
Michael Wright63c168a2015-12-04 17:59:42 +0000210}
211void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
212 AChoreographer_frameCallback callback, void* data, long delayMillis) {
213 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
Santos Cordon458d3df2019-02-20 18:09:00 +0000214 callback, nullptr, data, ms2ns(delayMillis));
215}
216void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
217 AChoreographer_frameCallback64 callback, void* data) {
218 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
219 nullptr, callback, data, 0);
220}
221void 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));
Michael Wright63c168a2015-12-04 17:59:42 +0000225}