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

Commit 3da8d274 authored by Brian Anderson's avatar Brian Anderson
Browse files

Surface unit tests for getFrameTimestamps.

Verifies the following:

1) The timestamps and fences aren't transferred if the
   feature isn't explicitly enabled.
2) Attempts to get the timestamps will fail if not enabled.
3) Timestamps are transferred if enabled.
4) The support for Present/Retire timestamps are properly
   queried from the ISurfaceComposer.
5) Timestamps correspond to the correct frame.
6) The consumer doesn't send the acquire fence back to the
   producer and a sync call isn't made to try and get it
   from the producer.
7) A sync call isn't made when no timestamps are requested.
8) If the consumer sent the producer fences, the consumer
   can get the timestamps without a sync call.
9) If there was no GL composite performed, a sync call
   isn't made to get a non-existant fence/time.
10) When asking for the retire or release time of the most
   recent frame, a sync call isn't made.
11) Requests for unsupported timestamps return an error and
   do not result in a sync call.

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

Change-Id: I6f728af0d4a0f431c9e47131da64584a589559e7
parent 50143b37
Loading
Loading
Loading
Loading
+11 −2
Original line number Original line Diff line number Diff line
@@ -116,13 +116,22 @@ class ProducerFrameEventHistory : public FrameEventHistory {
public:
public:
    ~ProducerFrameEventHistory() override;
    ~ProducerFrameEventHistory() override;


    void updateAcquireFence(
    // virtual for testing.
    virtual void updateAcquireFence(
            uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire);
            uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire);
    void applyDelta(const FrameEventHistoryDelta& delta);
    void applyDelta(const FrameEventHistoryDelta& delta);


    void updateSignalTimes();
    void updateSignalTimes();


private:
protected:
    void applyFenceDelta(FenceTimeline* timeline,
            std::shared_ptr<FenceTime>* dst,
            const FenceTime::Snapshot& src) const;

    // virtual for testing.
    virtual std::shared_ptr<FenceTime> createFenceTime(
            const sp<Fence>& fence) const;

    size_t mAcquireOffset{0};
    size_t mAcquireOffset{0};


    // The consumer updates it's timelines in Layer and SurfaceFlinger since
    // The consumer updates it's timelines in Layer and SurfaceFlinger since
+8 −3
Original line number Original line Diff line number Diff line
@@ -33,6 +33,8 @@ struct ANativeWindow_Buffer;


namespace android {
namespace android {


class ISurfaceComposer;

/*
/*
 * An implementation of ANativeWindow that feeds graphics buffers into a
 * An implementation of ANativeWindow that feeds graphics buffers into a
 * BufferQueue.
 * BufferQueue.
@@ -66,7 +68,8 @@ public:
     * the controlledByApp flag indicates that this Surface (producer) is
     * the controlledByApp flag indicates that this Surface (producer) is
     * controlled by the application. This flag is used at connect time.
     * controlled by the application. This flag is used at connect time.
     */
     */
    explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false);
    explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer,
            bool controlledByApp = false);


    /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this
    /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this
     * Surface was created with. Usually it's an error to use the
     * Surface was created with. Usually it's an error to use the
@@ -152,6 +155,9 @@ public:
protected:
protected:
    virtual ~Surface();
    virtual ~Surface();


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

private:
private:
    // can't be copied
    // can't be copied
    Surface& operator = (const Surface& rhs);
    Surface& operator = (const Surface& rhs);
@@ -245,7 +251,6 @@ protected:
    enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS };
    enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS };
    enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
    enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };


private:
    void querySupportedTimestampsLocked() const;
    void querySupportedTimestampsLocked() const;


    void freeAllBuffers();
    void freeAllBuffers();
@@ -399,7 +404,7 @@ private:


    // A cached copy of the FrameEventHistory maintained by the consumer.
    // A cached copy of the FrameEventHistory maintained by the consumer.
    bool mEnableFrameTimestamps = false;
    bool mEnableFrameTimestamps = false;
    ProducerFrameEventHistory mFrameEventHistory;
    std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory;
};
};


namespace view {
namespace view {
+47 −0
Original line number Original line Diff line number Diff line
@@ -24,13 +24,17 @@
#include <atomic>
#include <atomic>
#include <mutex>
#include <mutex>
#include <queue>
#include <queue>
#include <unordered_map>


namespace android {
namespace android {


class FenceToFenceTimeMap;

// A wrapper around fence that only implements isValid and getSignalTime.
// A wrapper around fence that only implements isValid and getSignalTime.
// It automatically closes the fence in a thread-safe manner once the signal
// It automatically closes the fence in a thread-safe manner once the signal
// time is known.
// time is known.
class FenceTime {
class FenceTime {
friend class FenceToFenceTimeMap;
public:
public:
    // An atomic snapshot of the FenceTime that is flattenable.
    // An atomic snapshot of the FenceTime that is flattenable.
    //
    //
@@ -107,15 +111,22 @@ public:
    // Returns a snapshot of the FenceTime in its current state.
    // Returns a snapshot of the FenceTime in its current state.
    Snapshot getSnapshot() const;
    Snapshot getSnapshot() const;


    void signalForTest(nsecs_t signalTime);

    // Override new and delete since this needs 8-byte alignment, which
    // Override new and delete since this needs 8-byte alignment, which
    // is not guaranteed on x86.
    // is not guaranteed on x86.
    static void* operator new(size_t nbytes) noexcept;
    static void* operator new(size_t nbytes) noexcept;
    static void operator delete(void *p);
    static void operator delete(void *p);


private:
private:
    // For tests only. If forceValidForTest is true, then getSignalTime will
    // never return SIGNAL_TIME_INVALID and isValid will always return true.
    FenceTime(const sp<Fence>& fence, bool forceValidForTest);

    enum class State {
    enum class State {
        VALID,
        VALID,
        INVALID,
        INVALID,
        FORCED_VALID_FOR_TEST,
    };
    };


    const State mState{State::INVALID};
    const State mState{State::INVALID};
@@ -156,6 +167,42 @@ private:
    std::queue<std::weak_ptr<FenceTime>> mQueue;
    std::queue<std::weak_ptr<FenceTime>> mQueue;
};
};


// Used by test code to create or get FenceTimes for a given Fence.
//
// By design, Fences cannot be signaled from user space. However, this class
// allows test code to set the apparent signalTime of a Fence and
// have it be visible to all FenceTimes. Release code should not use
// FenceToFenceTimeMap.
//
// FenceToFenceTimeMap keeps a weak reference to the FenceTime and automatically
// garbage collects entries every time a new FenceTime is created to avoid
// leaks. This prevents us from having to make the Fence destructor
// automatically notify that the underlying fence has been destroyed, which
// would affect release code paths. Garbage collecting so often is inefficient,
// but acceptable for testing.
//
// Since FenceTimes maintain a strong reference to underlying Fences, there
// should not be any aliasing issues where a new Fence happens to have the same
// address as a previous Fence; the previous entry will be garbage collected
// before the new one is added.
class FenceToFenceTimeMap {
public:
    // Create a new FenceTime with that wraps the provided Fence.
    std::shared_ptr<FenceTime> createFenceTimeForTest(const sp<Fence>& fence);

    // Signals all FenceTimes created through this class that are wrappers
    // around |fence|.
    void signalAllForTest(const sp<Fence>& fence, nsecs_t signalTime);

private:
    // Cleans up the entries that no longer have a strong reference.
    void garbageCollectLocked();

    mutable std::mutex mMutex;
    std::unordered_map<Fence*, std::vector<std::weak_ptr<FenceTime>>> mMap;
};


}; // namespace android
}; // namespace android


#endif // ANDROID_FENCE_TIME_H
#endif // ANDROID_FENCE_TIME_H
+32 −27
Original line number Original line Diff line number Diff line
@@ -241,33 +241,6 @@ void ProducerFrameEventHistory::updateAcquireFence(
    }
    }
}
}


static void applyFenceDelta(FenceTimeline* timeline,
        std::shared_ptr<FenceTime>* dst, const FenceTime::Snapshot& src) {
    if (CC_UNLIKELY(dst == nullptr)) {
        ALOGE("applyFenceDelta: dst is null.");
        return;
    }

    switch (src.state) {
        case FenceTime::Snapshot::State::EMPTY:
            return;
        case FenceTime::Snapshot::State::FENCE:
            if (CC_UNLIKELY((*dst)->isValid())) {
                ALOGE("applyFenceDelta: Unexpected fence.");
            }
            *dst = std::make_shared<FenceTime>(src.fence);
            timeline->push(*dst);
            return;
        case FenceTime::Snapshot::State::SIGNAL_TIME:
            if ((*dst)->isValid()) {
                (*dst)->applyTrustedSnapshot(src);
            } else {
                *dst = std::make_shared<FenceTime>(src.signalTime);
            }
            return;
    }
}

void ProducerFrameEventHistory::applyDelta(
void ProducerFrameEventHistory::applyDelta(
        const FrameEventHistoryDelta& delta) {
        const FrameEventHistoryDelta& delta) {
    for (auto& d : delta.mDeltas) {
    for (auto& d : delta.mDeltas) {
@@ -320,6 +293,38 @@ void ProducerFrameEventHistory::updateSignalTimes() {
    mReleaseTimeline.updateSignalTimes();
    mReleaseTimeline.updateSignalTimes();
}
}


void ProducerFrameEventHistory::applyFenceDelta(FenceTimeline* timeline,
        std::shared_ptr<FenceTime>* dst, const FenceTime::Snapshot& src) const {
    if (CC_UNLIKELY(dst == nullptr)) {
        ALOGE("applyFenceDelta: dst is null.");
        return;
    }

    switch (src.state) {
        case FenceTime::Snapshot::State::EMPTY:
            return;
        case FenceTime::Snapshot::State::FENCE:
            if (CC_UNLIKELY((*dst)->isValid())) {
                ALOGE("applyFenceDelta: Unexpected fence.");
            }
            *dst = createFenceTime(src.fence);
            timeline->push(*dst);
            return;
        case FenceTime::Snapshot::State::SIGNAL_TIME:
            if ((*dst)->isValid()) {
                (*dst)->applyTrustedSnapshot(src);
            } else {
                *dst = std::make_shared<FenceTime>(src.signalTime);
            }
            return;
    }
}

std::shared_ptr<FenceTime> ProducerFrameEventHistory::createFenceTime(
        const sp<Fence>& fence) const {
    return std::make_shared<FenceTime>(fence);
}



// ============================================================================
// ============================================================================
// ConsumerFrameEventHistory
// ConsumerFrameEventHistory
+16 −13
Original line number Original line Diff line number Diff line
@@ -52,7 +52,8 @@ Surface::Surface(
      mQueriedSupportedTimestamps(false),
      mQueriedSupportedTimestamps(false),
      mFrameTimestampsSupportsPresent(false),
      mFrameTimestampsSupportsPresent(false),
      mFrameTimestampsSupportsRetire(false),
      mFrameTimestampsSupportsRetire(false),
      mEnableFrameTimestamps(false)
      mEnableFrameTimestamps(false),
      mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>())
{
{
    // Initialize the ANativeWindow function pointers.
    // Initialize the ANativeWindow function pointers.
    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
@@ -96,6 +97,10 @@ Surface::~Surface() {
    }
    }
}
}


sp<ISurfaceComposer> Surface::composerService() const {
    return ComposerService::getComposerService();
}

sp<IGraphicBufferProducer> Surface::getIGraphicBufferProducer() const {
sp<IGraphicBufferProducer> Surface::getIGraphicBufferProducer() const {
    return mGraphicBufferProducer;
    return mGraphicBufferProducer;
}
}
@@ -203,7 +208,7 @@ status_t Surface::getFrameTimestamps(uint64_t frameNumber,
        return BAD_VALUE;
        return BAD_VALUE;
    }
    }


    FrameEvents* events = mFrameEventHistory.getFrame(frameNumber);
    FrameEvents* events = mFrameEventHistory->getFrame(frameNumber);
    if (events == nullptr) {
    if (events == nullptr) {
        // If the entry isn't available in the producer, it's definitely not
        // If the entry isn't available in the producer, it's definitely not
        // available in the consumer.
        // available in the consumer.
@@ -216,8 +221,8 @@ status_t Surface::getFrameTimestamps(uint64_t frameNumber,
            outDisplayPresentTime, outDisplayRetireTime, outReleaseTime)) {
            outDisplayPresentTime, outDisplayRetireTime, outReleaseTime)) {
        FrameEventHistoryDelta delta;
        FrameEventHistoryDelta delta;
        mGraphicBufferProducer->getFrameTimestamps(&delta);
        mGraphicBufferProducer->getFrameTimestamps(&delta);
        mFrameEventHistory.applyDelta(delta);
        mFrameEventHistory->applyDelta(delta);
        events = mFrameEventHistory.getFrame(frameNumber);
        events = mFrameEventHistory->getFrame(frameNumber);
    }
    }


    if (events == nullptr) {
    if (events == nullptr) {
@@ -396,7 +401,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
    }
    }


    if (enableFrameTimestamps) {
    if (enableFrameTimestamps) {
         mFrameEventHistory.applyDelta(frameTimestamps);
         mFrameEventHistory->applyDelta(frameTimestamps);
    }
    }


    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
@@ -590,16 +595,16 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
    }
    }


    if (mEnableFrameTimestamps) {
    if (mEnableFrameTimestamps) {
        mFrameEventHistory.applyDelta(output.frameTimestamps);
        mFrameEventHistory->applyDelta(output.frameTimestamps);
        // Update timestamps with the local acquire fence.
        // Update timestamps with the local acquire fence.
        // The consumer doesn't send it back to prevent us from having two
        // The consumer doesn't send it back to prevent us from having two
        // file descriptors of the same fence.
        // file descriptors of the same fence.
        mFrameEventHistory.updateAcquireFence(mNextFrameNumber,
        mFrameEventHistory->updateAcquireFence(mNextFrameNumber,
                std::make_shared<FenceTime>(std::move(fence)));
                std::make_shared<FenceTime>(std::move(fence)));


        // Cache timestamps of signaled fences so we can close their file
        // Cache timestamps of signaled fences so we can close their file
        // descriptors.
        // descriptors.
        mFrameEventHistory.updateSignalTimes();
        mFrameEventHistory->updateSignalTimes();
    }
    }


    mLastFrameNumber = mNextFrameNumber;
    mLastFrameNumber = mNextFrameNumber;
@@ -638,8 +643,7 @@ void Surface::querySupportedTimestampsLocked() const {
    mQueriedSupportedTimestamps = true;
    mQueriedSupportedTimestamps = true;


    std::vector<FrameEvent> supportedFrameTimestamps;
    std::vector<FrameEvent> supportedFrameTimestamps;
    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
    status_t err = composerService()->getSupportedFrameTimestamps(
    status_t err = composer->getSupportedFrameTimestamps(
            &supportedFrameTimestamps);
            &supportedFrameTimestamps);


    if (err != NO_ERROR) {
    if (err != NO_ERROR) {
@@ -668,9 +672,8 @@ int Surface::query(int what, int* value) const {
                }
                }
                break;
                break;
            case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
            case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
                sp<ISurfaceComposer> composer(
                if (composerService()->authenticateSurfaceTexture(
                        ComposerService::getComposerService());
                        mGraphicBufferProducer)) {
                if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) {
                    *value = 1;
                    *value = 1;
                } else {
                } else {
                    *value = 0;
                    *value = 0;
Loading