Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 15bd9007 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add types for native Choreographer to ensure ordering" into main

parents 80925c21 475c4131
Loading
Loading
Loading
Loading
+32 −14
Original line number Diff line number Diff line
@@ -143,9 +143,9 @@ Choreographer::~Choreographer() {
void Choreographer::postFrameCallbackDelayed(AChoreographer_frameCallback cb,
                                             AChoreographer_frameCallback64 cb64,
                                             AChoreographer_vsyncCallback vsyncCallback, void* data,
                                             nsecs_t delay) {
                                             nsecs_t delay, CallbackType callbackType) {
    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    FrameCallback callback{cb, cb64, vsyncCallback, data, now + delay};
    FrameCallback callback{cb, cb64, vsyncCallback, data, now + delay, callbackType};
    {
        std::lock_guard<std::mutex> _l{mLock};
        mFrameCallbacks.push(callback);
@@ -285,18 +285,8 @@ void Choreographer::handleRefreshRateUpdates() {
    }
}

void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t,
                                  VsyncEventData vsyncEventData) {
    std::vector<FrameCallback> callbacks{};
    {
        std::lock_guard<std::mutex> _l{mLock};
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) {
            callbacks.push_back(mFrameCallbacks.top());
            mFrameCallbacks.pop();
        }
    }
    mLastVsyncEventData = vsyncEventData;
void Choreographer::dispatchCallbacks(const std::vector<FrameCallback>& callbacks,
                                      VsyncEventData vsyncEventData, nsecs_t timestamp) {
    for (const auto& cb : callbacks) {
        if (cb.vsyncCallback != nullptr) {
            ATRACE_FORMAT("AChoreographer_vsyncCallback %" PRId64,
@@ -319,6 +309,34 @@ void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t
    }
}

void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t,
                                  VsyncEventData vsyncEventData) {
    std::vector<FrameCallback> animationCallbacks{};
    std::vector<FrameCallback> inputCallbacks{};
    {
        std::lock_guard<std::mutex> _l{mLock};
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) {
            if (mFrameCallbacks.top().callbackType == CALLBACK_INPUT) {
                inputCallbacks.push_back(mFrameCallbacks.top());
            } else {
                animationCallbacks.push_back(mFrameCallbacks.top());
            }
            mFrameCallbacks.pop();
        }
    }
    mLastVsyncEventData = vsyncEventData;
    // Callbacks with type CALLBACK_INPUT should always run first
    {
        ATRACE_FORMAT("CALLBACK_INPUT");
        dispatchCallbacks(inputCallbacks, vsyncEventData, timestamp);
    }
    {
        ATRACE_FORMAT("CALLBACK_ANIMATION");
        dispatchCallbacks(animationCallbacks, vsyncEventData, timestamp);
    }
}

void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) {
    ALOGV("choreographer %p ~ received hotplug event (displayId=%s, connected=%s), ignoring.", this,
          to_string(displayId).c_str(), toString(connected));
+9 −1
Original line number Diff line number Diff line
@@ -28,12 +28,18 @@
namespace android {
using gui::VsyncEventData;

enum CallbackType : int8_t {
    CALLBACK_INPUT,
    CALLBACK_ANIMATION,
};

struct FrameCallback {
    AChoreographer_frameCallback callback;
    AChoreographer_frameCallback64 callback64;
    AChoreographer_vsyncCallback vsyncCallback;
    void* data;
    nsecs_t dueTime;
    CallbackType callbackType;

    inline bool operator<(const FrameCallback& rhs) const {
        // Note that this is intentionally flipped because we want callbacks due sooner to be at
@@ -78,7 +84,7 @@ public:
    void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
                                  AChoreographer_frameCallback64 cb64,
                                  AChoreographer_vsyncCallback vsyncCallback, void* data,
                                  nsecs_t delay);
                                  nsecs_t delay, CallbackType callbackType);
    void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data)
            EXCLUDES(gChoreographers.lock);
    void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
@@ -109,6 +115,8 @@ private:

    void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
                       VsyncEventData vsyncEventData) override;
    void dispatchCallbacks(const std::vector<FrameCallback>&, VsyncEventData vsyncEventData,
                           nsecs_t timestamp);
    void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
    void dispatchHotplugConnectionError(nsecs_t timestamp, int32_t connectionError) override;
    void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
+2 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ cc_test {
        "BLASTBufferQueue_test.cpp",
        "BufferItemConsumer_test.cpp",
        "BufferQueue_test.cpp",
        "Choreographer_test.cpp",
        "CompositorTiming_test.cpp",
        "CpuConsumer_test.cpp",
        "EndToEndNativeInputTest.cpp",
@@ -61,6 +62,7 @@ cc_test {
        "libSurfaceFlingerProp",
        "libGLESv1_CM",
        "libinput",
        "libnativedisplay",
    ],

    static_libs: [
+88 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "Choreographer_test"

#include <android-base/stringprintf.h>
#include <android/choreographer.h>
#include <gtest/gtest.h>
#include <gui/Choreographer.h>
#include <utils/Looper.h>
#include <chrono>
#include <future>
#include <string>

namespace android {
class ChoreographerTest : public ::testing::Test {};

struct VsyncCallback {
    std::atomic<bool> completePromise{false};
    std::chrono::nanoseconds frameTime{0LL};
    std::chrono::nanoseconds receivedCallbackTime{0LL};

    void onVsyncCallback(const AChoreographerFrameCallbackData* callbackData) {
        frameTime = std::chrono::nanoseconds{
                AChoreographerFrameCallbackData_getFrameTimeNanos(callbackData)};
        receivedCallbackTime = std::chrono::nanoseconds{systemTime(SYSTEM_TIME_MONOTONIC)};
        completePromise.store(true);
    }

    bool callbackReceived() { return completePromise.load(); }
};

static void vsyncCallback(const AChoreographerFrameCallbackData* callbackData, void* data) {
    VsyncCallback* cb = static_cast<VsyncCallback*>(data);
    cb->onVsyncCallback(callbackData);
}

TEST_F(ChoreographerTest, InputCallbackBeforeAnimation) {
    sp<Looper> looper = Looper::prepare(0);
    Choreographer* choreographer = Choreographer::getForThread();
    VsyncCallback animationCb;
    VsyncCallback inputCb;

    choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &animationCb, 0,
                                            CALLBACK_ANIMATION);
    choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &inputCb, 0,
                                            CALLBACK_INPUT);

    nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
    nsecs_t currTime;
    int pollResult;
    do {
        pollResult = looper->pollOnce(16);
        currTime = systemTime(SYSTEM_TIME_MONOTONIC);
    } while (!(inputCb.callbackReceived() && animationCb.callbackReceived()) &&
             (pollResult != Looper::POLL_TIMEOUT && pollResult != Looper::POLL_ERROR) &&
             (currTime - startTime < 3000));

    ASSERT_TRUE(inputCb.callbackReceived()) << "did not receive input callback";
    ASSERT_TRUE(animationCb.callbackReceived()) << "did not receive animation callback";

    ASSERT_EQ(inputCb.frameTime, animationCb.frameTime)
            << android::base::StringPrintf("input and animation callback frame times don't match. "
                                           "inputFrameTime=%lld  animationFrameTime=%lld",
                                           inputCb.frameTime.count(),
                                           animationCb.frameTime.count());

    ASSERT_LT(inputCb.receivedCallbackTime, animationCb.receivedCallbackTime)
            << android::base::StringPrintf("input callback was not called first. "
                                           "inputCallbackTime=%lld  animationCallbackTime=%lld",
                                           inputCb.frameTime.count(),
                                           animationCb.frameTime.count());
}

} // namespace android
 No newline at end of file
+7 −5
Original line number Diff line number Diff line
@@ -148,29 +148,31 @@ AChoreographer* AChoreographer_getInstance() {
void AChoreographer_postFrameCallback(AChoreographer* choreographer,
                                      AChoreographer_frameCallback callback, void* data) {
    AChoreographer_to_Choreographer(choreographer)
            ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, 0);
            ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, 0, CALLBACK_ANIMATION);
}
void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
                                             AChoreographer_frameCallback callback, void* data,
                                             long delayMillis) {
    AChoreographer_to_Choreographer(choreographer)
            ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, ms2ns(delayMillis));
            ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, ms2ns(delayMillis),
                                       CALLBACK_ANIMATION);
}
void AChoreographer_postVsyncCallback(AChoreographer* choreographer,
                                      AChoreographer_vsyncCallback callback, void* data) {
    AChoreographer_to_Choreographer(choreographer)
            ->postFrameCallbackDelayed(nullptr, nullptr, callback, data, 0);
            ->postFrameCallbackDelayed(nullptr, nullptr, callback, data, 0, CALLBACK_ANIMATION);
}
void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
                                        AChoreographer_frameCallback64 callback, void* data) {
    AChoreographer_to_Choreographer(choreographer)
            ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, 0);
            ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, 0, CALLBACK_ANIMATION);
}
void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
                                               AChoreographer_frameCallback64 callback, void* data,
                                               uint32_t delayMillis) {
    AChoreographer_to_Choreographer(choreographer)
            ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, ms2ns(delayMillis));
            ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, ms2ns(delayMillis),
                                       CALLBACK_ANIMATION);
}
void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
                                                AChoreographer_refreshRateCallback callback,