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 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 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 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; 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 107 Choreographer::Choreographer(const sp<Looper>& looper) : 108 DisplayEventDispatcher(looper), mLooper(looper), mThreadId(std::this_thread::get_id()) { 109 } 110 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 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. 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 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 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 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 194 static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) { 195 return reinterpret_cast<Choreographer*>(choreographer); 196 } 197 198 static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) { 199 return reinterpret_cast<AChoreographer*>(choreographer); 200 } 201 202 AChoreographer* AChoreographer_getInstance() { 203 return Choreographer_to_AChoreographer(Choreographer::getForThread()); 204 } 205 206 void AChoreographer_postFrameCallback(AChoreographer* choreographer, 207 AChoreographer_frameCallback callback, void* data) { 208 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( 209 callback, nullptr, data, 0); 210 } 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 } 216 void AChoreographer_postFrameCallback64(AChoreographer* choreographer, 217 AChoreographer_frameCallback64 callback, void* data) { 218 AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed( 219 nullptr, callback, data, 0); 220 } 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