Home | History | Annotate | Download | only in android
      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