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

Commit 0a61b0c8 authored by Brian Anderson's avatar Brian Anderson
Browse files

EGL: Add eglGetCompositorTimingANDROID.

Exposes the composite deadline, composite interval, and
the composite to present latency.

A history of composite and present fences are stored.
When the present fence's timestamp becomes known,
the composite to present latency is updated with
sampling jitter removed.

The values are updated in the producer when timestamps
are enabled and on queue and dequeue.

The deadline is snapped to the next expected deadline
based on the current systemTime().

Test: adb shell /data/nativetest/libgui_test/libgui_test
    --gtest_filter=*GetFrameTimestamps*

Change-Id: I406814258613b984b56488236632494f2f61ff2e
parent 1049d1d0
Loading
Loading
Loading
Loading
+24 −3
Original line number Diff line number Diff line
@@ -95,6 +95,11 @@ struct FrameEvents {
    std::shared_ptr<FenceTime> releaseFence{FenceTime::NO_FENCE};
};

struct CompositorTiming {
    nsecs_t deadline{0};
    nsecs_t interval{16666667};
    nsecs_t presentLatency{0};
};

// A short history of frames that are synchronized between the consumer and
// producer via deltas.
@@ -111,6 +116,8 @@ public:

protected:
    std::array<FrameEvents, MAX_FRAME_HISTORY> mFrames;

    CompositorTiming mCompositorTiming;
};


@@ -119,6 +126,16 @@ class ProducerFrameEventHistory : public FrameEventHistory {
public:
    ~ProducerFrameEventHistory() override;

    // Public for testing.
    static nsecs_t snapToNextTick(
            nsecs_t timestamp, nsecs_t tickPhase, nsecs_t tickInterval);

    nsecs_t getNextCompositeDeadline(const nsecs_t now) const;
    nsecs_t getCompositeInterval() const { return mCompositorTiming.interval; }
    nsecs_t getCompositeToPresentLatency() const {
        return mCompositorTiming.presentLatency;
    }

    // virtual for testing.
    virtual void updateAcquireFence(
            uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire);
@@ -189,12 +206,15 @@ class ConsumerFrameEventHistory : public FrameEventHistory {
public:
    ~ConsumerFrameEventHistory() override;

    void initializeCompositorTiming(const CompositorTiming& compositorTiming);

    void addQueue(const NewFrameEventsEntry& newEntry);
    void addLatch(uint64_t frameNumber, nsecs_t latchTime);
    void addPreComposition(uint64_t frameNumber, nsecs_t refreshStartTime);
    void addPostComposition(uint64_t frameNumber,
            const std::shared_ptr<FenceTime>& gpuCompositionDone,
            const std::shared_ptr<FenceTime>& displayPresent);
            const std::shared_ptr<FenceTime>& displayPresent,
            const CompositorTiming& compositorTiming);
    void addRetire(uint64_t frameNumber,
            const std::shared_ptr<FenceTime>& displayRetire);
    void addRelease(uint64_t frameNumber, nsecs_t dequeueReadyTime,
@@ -244,7 +264,7 @@ public:
            size_t& count);

private:
    static size_t minFlattenedSize();
    static constexpr size_t minFlattenedSize();

    size_t mIndex{0};
    uint64_t mFrameNumber{0};
@@ -306,9 +326,10 @@ public:
            size_t& count);

private:
    static size_t minFlattenedSize();
    static constexpr size_t minFlattenedSize();

    std::vector<FrameEventsDelta> mDeltas;
    CompositorTiming mCompositorTiming;
};


+9 −2
Original line number Diff line number Diff line
@@ -137,12 +137,18 @@ public:
    status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
            sp<Fence>* outFence, float outTransformMatrix[16]);

    status_t getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration);

    /* Enables or disables frame timestamp tracking. It is disabled by default
     * to avoid overhead during queue and dequeue for applications that don't
     * need the feature. If disabled, calls to getFrameTimestamps will fail.
     */
    void enableFrameTimestamps(bool enable);

    status_t getCompositorTiming(
            nsecs_t* compositeDeadline, nsecs_t* compositeInterval,
            nsecs_t* compositeToPresentLatency);

    // See IGraphicBufferProducer::getFrameTimestamps
    status_t getFrameTimestamps(uint64_t frameNumber,
            nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime,
@@ -150,7 +156,6 @@ public:
            nsecs_t* outLastRefreshStartTime, nsecs_t* outGlCompositionDoneTime,
            nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
            nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime);
    status_t getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration);

    status_t getUniqueId(uint64_t* outId) const;

@@ -159,6 +164,7 @@ protected:

    // Virtual for testing.
    virtual sp<ISurfaceComposer> composerService() const;
    virtual nsecs_t now() const;

private:
    // can't be copied
@@ -206,10 +212,11 @@ private:
    int dispatchSetSurfaceDamage(va_list args);
    int dispatchSetSharedBufferMode(va_list args);
    int dispatchSetAutoRefresh(va_list args);
    int dispatchGetDisplayRefreshCycleDuration(va_list args);
    int dispatchGetNextFrameId(va_list args);
    int dispatchEnableFrameTimestamps(va_list args);
    int dispatchGetCompositorTiming(va_list args);
    int dispatchGetFrameTimestamps(va_list args);
    int dispatchGetDisplayRefreshCycleDuration(va_list args);

protected:
    virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
+41 −7
Original line number Diff line number Diff line
@@ -235,6 +235,23 @@ void FrameEventHistory::dump(String8& outString) const {

ProducerFrameEventHistory::~ProducerFrameEventHistory() = default;

nsecs_t ProducerFrameEventHistory::snapToNextTick(
        nsecs_t timestamp, nsecs_t tickPhase, nsecs_t tickInterval) {
    nsecs_t tickOffset = (tickPhase - timestamp) % tickInterval;
    // Integer modulo rounds towards 0 and not -inf before taking the remainder,
    // so adjust the offset if it is negative.
    if (tickOffset < 0) {
        tickOffset += tickInterval;
    }
    return timestamp + tickOffset;
}

nsecs_t ProducerFrameEventHistory::getNextCompositeDeadline(
        const nsecs_t now) const{
    return snapToNextTick(
            now, mCompositorTiming.deadline, mCompositorTiming.interval);
}

void ProducerFrameEventHistory::updateAcquireFence(
        uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire) {
    FrameEvents* frame = getFrame(frameNumber, &mAcquireOffset);
@@ -256,6 +273,8 @@ void ProducerFrameEventHistory::updateAcquireFence(

void ProducerFrameEventHistory::applyDelta(
        const FrameEventHistoryDelta& delta) {
    mCompositorTiming = delta.mCompositorTiming;

    for (auto& d : delta.mDeltas) {
        // Avoid out-of-bounds access.
        if (d.mIndex >= mFrames.size()) {
@@ -346,6 +365,11 @@ std::shared_ptr<FenceTime> ProducerFrameEventHistory::createFenceTime(

ConsumerFrameEventHistory::~ConsumerFrameEventHistory() = default;

void ConsumerFrameEventHistory::initializeCompositorTiming(
        const CompositorTiming& compositorTiming) {
    mCompositorTiming = compositorTiming;
}

void ConsumerFrameEventHistory::addQueue(const NewFrameEventsEntry& newEntry) {
    // Overwrite all fields of the frame with default values unless set here.
    FrameEvents newTimestamps;
@@ -393,7 +417,10 @@ void ConsumerFrameEventHistory::addPreComposition(

void ConsumerFrameEventHistory::addPostComposition(uint64_t frameNumber,
        const std::shared_ptr<FenceTime>& gpuCompositionDone,
        const std::shared_ptr<FenceTime>& displayPresent) {
        const std::shared_ptr<FenceTime>& displayPresent,
        const CompositorTiming& compositorTiming) {
    mCompositorTiming = compositorTiming;

    FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
    if (frame == nullptr) {
        ALOGE_IF(mProducerWantsEvents,
@@ -450,6 +477,8 @@ void ConsumerFrameEventHistory::getFrameDelta(

void ConsumerFrameEventHistory::getAndResetDelta(
        FrameEventHistoryDelta* delta) {
    delta->mCompositorTiming = mCompositorTiming;

    // Write these in order of frame number so that it is easy to
    // add them to a FenceTimeline in the proper order producer side.
    delta->mDeltas.reserve(mFramesDirty.size());
@@ -499,9 +528,8 @@ FrameEventsDelta::FrameEventsDelta(
    }
}

size_t FrameEventsDelta::minFlattenedSize() {
    constexpr size_t min =
            sizeof(FrameEventsDelta::mFrameNumber) +
constexpr size_t FrameEventsDelta::minFlattenedSize() {
    return sizeof(FrameEventsDelta::mFrameNumber) +
            sizeof(uint8_t) + // mIndex
            sizeof(uint8_t) + // mAddPostCompositeCalled
            sizeof(uint8_t) + // mAddRetireCalled
@@ -512,7 +540,6 @@ size_t FrameEventsDelta::minFlattenedSize() {
            sizeof(FrameEventsDelta::mFirstRefreshStartTime) +
            sizeof(FrameEventsDelta::mLastRefreshStartTime) +
            sizeof(FrameEventsDelta::mDequeueReadyTime);
    return min;
}

// Flattenable implementation
@@ -618,6 +645,8 @@ status_t FrameEventsDelta::unflatten(void const*& buffer, size_t& size,

FrameEventHistoryDelta& FrameEventHistoryDelta::operator=(
        FrameEventHistoryDelta&& src) {
    mCompositorTiming = src.mCompositorTiming;

    if (CC_UNLIKELY(!mDeltas.empty())) {
        ALOGE("FrameEventHistoryDelta: Clobbering history.");
    }
@@ -626,8 +655,9 @@ FrameEventHistoryDelta& FrameEventHistoryDelta::operator=(
    return *this;
}

size_t FrameEventHistoryDelta::minFlattenedSize() {
    return sizeof(uint32_t);
constexpr size_t FrameEventHistoryDelta::minFlattenedSize() {
    return sizeof(uint32_t) + // mDeltas.size()
            sizeof(mCompositorTiming);
}

size_t FrameEventHistoryDelta::getFlattenedSize() const {
@@ -654,6 +684,8 @@ status_t FrameEventHistoryDelta::flatten(
        return NO_MEMORY;
    }

    FlattenableUtils::write(buffer, size, mCompositorTiming);

    FlattenableUtils::write(
            buffer, size, static_cast<uint32_t>(mDeltas.size()));
    for (auto& d : mDeltas) {
@@ -671,6 +703,8 @@ status_t FrameEventHistoryDelta::unflatten(
        return NO_MEMORY;
    }

    FlattenableUtils::read(buffer, size, mCompositorTiming);

    uint32_t deltaCount = 0;
    FlattenableUtils::read(buffer, size, deltaCount);
    if (deltaCount > FrameEventHistory::MAX_FRAME_HISTORY) {
+63 −18
Original line number Diff line number Diff line
@@ -102,6 +102,10 @@ sp<ISurfaceComposer> Surface::composerService() const {
    return ComposerService::getComposerService();
}

nsecs_t Surface::now() const {
    return systemTime();
}

sp<IGraphicBufferProducer> Surface::getIGraphicBufferProducer() const {
    return mGraphicBufferProducer;
}
@@ -144,11 +148,51 @@ status_t Surface::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
            outTransformMatrix);
}

status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) {
    ATRACE_CALL();

    DisplayStatInfo stats;
    status_t err = composerService()->getDisplayStats(NULL, &stats);

    *outRefreshDuration = stats.vsyncPeriod;

    return NO_ERROR;
}

void Surface::enableFrameTimestamps(bool enable) {
    Mutex::Autolock lock(mMutex);
    // If going from disabled to enabled, get the initial values for
    // compositor and display timing.
    if (!mEnableFrameTimestamps && enable) {
        FrameEventHistoryDelta delta;
        mGraphicBufferProducer->getFrameTimestamps(&delta);
        mFrameEventHistory->applyDelta(delta);
    }
    mEnableFrameTimestamps = enable;
}

status_t Surface::getCompositorTiming(
        nsecs_t* compositeDeadline, nsecs_t* compositeInterval,
        nsecs_t* compositeToPresentLatency) {
    Mutex::Autolock lock(mMutex);
    if (!mEnableFrameTimestamps) {
        return INVALID_OPERATION;
    }

    if (compositeDeadline != nullptr) {
        *compositeDeadline =
                mFrameEventHistory->getNextCompositeDeadline(now());
    }
    if (compositeInterval != nullptr) {
        *compositeInterval = mFrameEventHistory->getCompositeInterval();
    }
    if (compositeToPresentLatency != nullptr) {
        *compositeToPresentLatency =
                mFrameEventHistory->getCompositeToPresentLatency();
    }
    return NO_ERROR;
}

static bool checkConsumerForUpdates(
        const FrameEvents* e, const uint64_t lastFrameNumber,
        const nsecs_t* outLatchTime,
@@ -262,16 +306,6 @@ status_t Surface::getFrameTimestamps(uint64_t frameNumber,

    return NO_ERROR;
}
status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) {
    ATRACE_CALL();

    DisplayStatInfo stats;
    status_t err = composerService()->getDisplayStats(NULL, &stats);

    *outRefreshDuration = stats.vsyncPeriod;

    return NO_ERROR;
}

int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
    Surface* c = getSelf(window);
@@ -833,18 +867,21 @@ int Surface::perform(int operation, va_list args)
    case NATIVE_WINDOW_SET_AUTO_REFRESH:
        res = dispatchSetAutoRefresh(args);
        break;
    case NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION:
        res = dispatchGetDisplayRefreshCycleDuration(args);
        break;
    case NATIVE_WINDOW_GET_NEXT_FRAME_ID:
        res = dispatchGetNextFrameId(args);
        break;
    case NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS:
        res = dispatchEnableFrameTimestamps(args);
        break;
    case NATIVE_WINDOW_GET_COMPOSITOR_TIMING:
        res = dispatchGetCompositorTiming(args);
        break;
    case NATIVE_WINDOW_GET_FRAME_TIMESTAMPS:
        res = dispatchGetFrameTimestamps(args);
        break;
    case NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION:
        res = dispatchGetDisplayRefreshCycleDuration(args);
        break;
    default:
        res = NAME_NOT_FOUND;
        break;
@@ -965,6 +1002,11 @@ int Surface::dispatchSetAutoRefresh(va_list args) {
    return setAutoRefresh(autoRefresh);
}

int Surface::dispatchGetDisplayRefreshCycleDuration(va_list args) {
    nsecs_t* outRefreshDuration = va_arg(args, int64_t*);
    return getDisplayRefreshCycleDuration(outRefreshDuration);
}

int Surface::dispatchGetNextFrameId(va_list args) {
    uint64_t* nextFrameId = va_arg(args, uint64_t*);
    *nextFrameId = getNextFrameNumber();
@@ -977,6 +1019,14 @@ int Surface::dispatchEnableFrameTimestamps(va_list args) {
    return NO_ERROR;
}

int Surface::dispatchGetCompositorTiming(va_list args) {
    nsecs_t* compositeDeadline = va_arg(args, int64_t*);
    nsecs_t* compositeInterval = va_arg(args, int64_t*);
    nsecs_t* compositeToPresentLatency = va_arg(args, int64_t*);
    return getCompositorTiming(compositeDeadline, compositeInterval,
            compositeToPresentLatency);
}

int Surface::dispatchGetFrameTimestamps(va_list args) {
    uint64_t frameId = va_arg(args, uint64_t);
    nsecs_t* outRequestedPresentTime = va_arg(args, int64_t*);
@@ -996,11 +1046,6 @@ int Surface::dispatchGetFrameTimestamps(va_list args) {
            outDisplayRetireTime, outDequeueReadyTime, outReleaseTime);
}

int Surface::dispatchGetDisplayRefreshCycleDuration(va_list args) {
    nsecs_t* outRefreshDuration = va_arg(args, int64_t*);
    return getDisplayRefreshCycleDuration(outRefreshDuration);
}

int Surface::connect(int api) {
    static sp<IProducerListener> listener = new DummyProducerListener();
    return connect(api, listener);
+294 −13

File changed.

Preview size limit exceeded, changes collapsed.

Loading