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

Commit c0f27677 authored by Rachel Lee's avatar Rachel Lee Committed by Android (Google) Code Review
Browse files

Merge "Send multiple scheduler frame timelines."

parents af2cd9ae 6b180700
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -130,6 +130,19 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) {
    return 1; // keep the callback
}

void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event,
                                                    VsyncEventData* outVsyncEventData) const {
    for (size_t i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) {
        DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline =
                event.vsync.frameTimelines[i];
        outVsyncEventData->frameTimelines[i] = {.id = receiverTimeline.vsyncId,
                                                .deadlineTimestamp =
                                                        receiverTimeline.deadlineTimestamp,
                                                .expectedPresentTime =
                                                        receiverTimeline.expectedVSyncTimestamp};
    }
}

bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
                                                  PhysicalDisplayId* outDisplayId,
                                                  uint32_t* outCount,
@@ -154,6 +167,9 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
                    outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp;
                    outVsyncEventData->frameInterval = ev.vsync.frameInterval;
                    outVsyncEventData->expectedPresentTime = ev.vsync.expectedVSyncTimestamp;
                    outVsyncEventData->preferredFrameTimelineIndex =
                            ev.vsync.preferredFrameTimelineIndex;
                    populateFrameTimelines(ev, outVsyncEventData);
                    break;
                case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
                    dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
+24 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <gui/DisplayEventReceiver.h>
#include <utils/Log.h>
#include <utils/Looper.h>
#include <array>

namespace android {
using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
@@ -36,6 +37,26 @@ struct VsyncEventData {

    // The anticipated Vsync present time.
    int64_t expectedPresentTime = 0;

    struct FrameTimeline {
        // The Vsync Id corresponsing to this vsync event. This will be used to
        // populate ISurfaceComposer::setFrameTimelineVsync and
        // SurfaceComposerClient::setFrameTimelineVsync
        int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID;

        // The deadline in CLOCK_MONOTONIC that the app needs to complete its
        // frame by (both on the CPU and the GPU)
        int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max();

        // The anticipated Vsync present time.
        int64_t expectedPresentTime = 0;
    };

    // Sorted possible frame timelines.
    std::array<FrameTimeline, DisplayEventReceiver::kFrameTimelinesLength> frameTimelines;

    // Index into the frameTimelines that represents the platform's preferred frame timeline.
    size_t preferredFrameTimelineIndex = std::numeric_limits<size_t>::max();
};

class DisplayEventDispatcher : public LooperCallback {
@@ -77,5 +98,8 @@ private:

    bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
                              uint32_t* outCount, VsyncEventData* outVsyncEventData);

    void populateFrameTimelines(const DisplayEventReceiver::Event& event,
                                VsyncEventData* outVsyncEventData) const;
};
} // namespace android
+9 −0
Original line number Diff line number Diff line
@@ -49,6 +49,9 @@ static inline constexpr uint32_t fourcc(char c1, char c2, char c3, char c4) {
// ----------------------------------------------------------------------------
class DisplayEventReceiver {
public:
    // Max amount of frame timelines is arbitrarily set to be reasonable.
    static constexpr int64_t kFrameTimelinesLength = 7;

    enum {
        DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
        DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
@@ -77,6 +80,12 @@ public:
            nsecs_t deadlineTimestamp __attribute__((aligned(8)));
            nsecs_t frameInterval __attribute__((aligned(8)));
            int64_t vsyncId;
            size_t preferredFrameTimelineIndex __attribute__((aligned(8)));
            struct FrameTimeline {
                nsecs_t expectedVSyncTimestamp __attribute__((aligned(8)));
                nsecs_t deadlineTimestamp __attribute__((aligned(8)));
                int64_t vsyncId;
            } frameTimelines[kFrameTimelinesLength];
        };

        struct Hotplug {
+11 −23
Original line number Diff line number Diff line
@@ -100,17 +100,10 @@ class Choreographer;
 * Implementation of AChoreographerFrameCallbackData.
 */
struct ChoreographerFrameCallbackDataImpl {
    struct FrameTimeline {
        int64_t vsyncId{0};
        int64_t expectedPresentTimeNanos{0};
        int64_t deadlineNanos{0};
    };

    int64_t frameTimeNanos{0};

    size_t frameTimelinesLength;

    std::vector<FrameTimeline> frameTimelines;
    std::array<VsyncEventData::FrameTimeline, DisplayEventReceiver::kFrameTimelinesLength>
            frameTimelines;

    size_t preferredFrameTimelineIndex;

@@ -456,14 +449,9 @@ bool Choreographer::inCallback() const {
}

ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const {
    std::vector<ChoreographerFrameCallbackDataImpl::FrameTimeline> frameTimelines;
    frameTimelines.push_back({.vsyncId = mLastVsyncEventData.id,
                              .expectedPresentTimeNanos = mLastVsyncEventData.expectedPresentTime,
                              .deadlineNanos = mLastVsyncEventData.deadlineTimestamp});
    return {.frameTimeNanos = timestamp,
            .frameTimelinesLength = 1,
            .preferredFrameTimelineIndex = 0,
            .frameTimelines = frameTimelines,
            .preferredFrameTimelineIndex = mLastVsyncEventData.preferredFrameTimelineIndex,
            .frameTimelines = mLastVsyncEventData.frameTimelines,
            .choreographer = this};
}

@@ -646,7 +634,7 @@ size_t AChoreographerFrameCallbackData_getFrameTimelinesLength(
            AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
    LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
                        "Data is only valid in callback");
    return frameCallbackData->frameTimelinesLength;
    return frameCallbackData->frameTimelines.size();
}
size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
        const AChoreographerFrameCallbackData* data) {
@@ -662,8 +650,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
            AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
    LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
                        "Data is only valid in callback");
    LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds");
    return frameCallbackData->frameTimelines[index].vsyncId;
    LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
    return frameCallbackData->frameTimelines[index].id;
}
int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(
        const AChoreographerFrameCallbackData* data, size_t index) {
@@ -671,8 +659,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(
            AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
    LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
                        "Data is only valid in callback");
    LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds");
    return frameCallbackData->frameTimelines[index].expectedPresentTimeNanos;
    LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
    return frameCallbackData->frameTimelines[index].expectedPresentTime;
}
int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline(
        const AChoreographerFrameCallbackData* data, size_t index) {
@@ -680,8 +668,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline(
            AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
    LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
                        "Data is only valid in callback");
    LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds");
    return frameCallbackData->frameTimelines[index].deadlineNanos;
    LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds");
    return frameCallbackData->frameTimelines[index].deadlineTimestamp;
}

AChoreographer* AChoreographer_create() {
+37 −8
Original line number Diff line number Diff line
@@ -355,14 +355,7 @@ void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp
    std::lock_guard<std::mutex> lock(mMutex);

    LOG_FATAL_IF(!mVSyncState);
    const int64_t vsyncId = [&] {
        if (mTokenManager != nullptr) {
            return mTokenManager->generateTokenForPredictions(
                    {timestamp, deadlineTimestamp, expectedVSyncTimestamp});
        }
        return FrameTimelineInfo::INVALID_VSYNC_ID;
    }();

    const int64_t vsyncId = generateToken(timestamp, deadlineTimestamp, expectedVSyncTimestamp);
    mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count,
                                       expectedVSyncTimestamp, deadlineTimestamp, vsyncId));
    mCondition.notify_all();
@@ -567,12 +560,48 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event,
    }
}

int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp,
                                   nsecs_t deadlineTimestamp) const {
    if (mTokenManager != nullptr) {
        return mTokenManager->generateTokenForPredictions(
                {timestamp, deadlineTimestamp, expectedVSyncTimestamp});
    }
    return FrameTimelineInfo::INVALID_VSYNC_ID;
}

void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const {
    // Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included.
    for (int multiplier = -DisplayEventReceiver::kFrameTimelinesLength + 1, currentIndex = 0;
         currentIndex < DisplayEventReceiver::kFrameTimelinesLength; multiplier++) {
        nsecs_t deadline = event.vsync.deadlineTimestamp + multiplier * event.vsync.frameInterval;
        // Valid possible frame timelines must have future values.
        if (deadline > event.header.timestamp) {
            if (multiplier == 0) {
                event.vsync.preferredFrameTimelineIndex = currentIndex;
                event.vsync.frameTimelines[currentIndex] =
                        {.vsyncId = event.vsync.vsyncId,
                         .deadlineTimestamp = event.vsync.deadlineTimestamp,
                         .expectedVSyncTimestamp = event.vsync.expectedVSyncTimestamp};
            } else {
                nsecs_t expectedVSync =
                        event.vsync.expectedVSyncTimestamp + multiplier * event.vsync.frameInterval;
                event.vsync.frameTimelines[currentIndex] =
                        {.vsyncId = generateToken(event.header.timestamp, expectedVSync, deadline),
                         .deadlineTimestamp = deadline,
                         .expectedVSyncTimestamp = expectedVSync};
            }
            currentIndex++;
        }
    }
}

void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
                                const DisplayEventConsumers& consumers) {
    for (const auto& consumer : consumers) {
        DisplayEventReceiver::Event copy = event;
        if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
            copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid);
            generateFrameTimeline(copy);
        }
        switch (consumer->postEvent(copy)) {
            case NO_ERROR:
Loading