|  | /* | 
|  | * Copyright 2016 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. | 
|  | */ | 
|  |  | 
|  | #ifndef ANDROID_GUI_FRAMETIMESTAMPS_H | 
|  | #define ANDROID_GUI_FRAMETIMESTAMPS_H | 
|  |  | 
|  | #include <ui/FenceTime.h> | 
|  | #include <utils/Flattenable.h> | 
|  | #include <utils/StrongPointer.h> | 
|  | #include <utils/Timers.h> | 
|  |  | 
|  | #include <array> | 
|  | #include <bitset> | 
|  | #include <vector> | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | struct FrameEvents; | 
|  | class FrameEventHistoryDelta; | 
|  | class String8; | 
|  |  | 
|  |  | 
|  | // Identifiers for all the events that may be recorded or reported. | 
|  | enum class FrameEvent { | 
|  | POSTED, | 
|  | REQUESTED_PRESENT, | 
|  | LATCH, | 
|  | ACQUIRE, | 
|  | FIRST_REFRESH_START, | 
|  | LAST_REFRESH_START, | 
|  | GPU_COMPOSITION_DONE, | 
|  | DISPLAY_PRESENT, | 
|  | DEQUEUE_READY, | 
|  | RELEASE, | 
|  | EVENT_COUNT, // Not an actual event. | 
|  | }; | 
|  |  | 
|  |  | 
|  | // A collection of timestamps corresponding to a single frame. | 
|  | struct FrameEvents { | 
|  | static constexpr auto EVENT_COUNT = | 
|  | static_cast<size_t>(FrameEvent::EVENT_COUNT); | 
|  | static_assert(EVENT_COUNT <= 32, "Event count sanity check failed."); | 
|  | static constexpr nsecs_t TIMESTAMP_PENDING = | 
|  | std::numeric_limits<nsecs_t>::max(); | 
|  |  | 
|  | static inline bool isValidTimestamp(nsecs_t time) { | 
|  | return time != TIMESTAMP_PENDING; | 
|  | } | 
|  |  | 
|  | bool hasPostedInfo() const; | 
|  | bool hasRequestedPresentInfo() const; | 
|  | bool hasLatchInfo() const; | 
|  | bool hasFirstRefreshStartInfo() const; | 
|  | bool hasLastRefreshStartInfo() const; | 
|  | bool hasAcquireInfo() const; | 
|  | bool hasGpuCompositionDoneInfo() const; | 
|  | bool hasDisplayPresentInfo() const; | 
|  | bool hasReleaseInfo() const; | 
|  | bool hasDequeueReadyInfo() const; | 
|  |  | 
|  | void checkFencesForCompletion(); | 
|  | void dump(String8& outString) const; | 
|  |  | 
|  | bool valid{false}; | 
|  | int connectId{0}; | 
|  | uint64_t frameNumber{0}; | 
|  |  | 
|  | // Whether or not certain points in the frame's life cycle have been | 
|  | // encountered help us determine if timestamps aren't available because | 
|  | // a) we'll just never get them or b) they're not ready yet. | 
|  | bool addPostCompositeCalled{false}; | 
|  | bool addReleaseCalled{false}; | 
|  |  | 
|  | nsecs_t postedTime{TIMESTAMP_PENDING}; | 
|  | nsecs_t requestedPresentTime{TIMESTAMP_PENDING}; | 
|  | nsecs_t latchTime{TIMESTAMP_PENDING}; | 
|  | nsecs_t firstRefreshStartTime{TIMESTAMP_PENDING}; | 
|  | nsecs_t lastRefreshStartTime{TIMESTAMP_PENDING}; | 
|  | nsecs_t dequeueReadyTime{TIMESTAMP_PENDING}; | 
|  |  | 
|  | std::shared_ptr<FenceTime> acquireFence{FenceTime::NO_FENCE}; | 
|  | std::shared_ptr<FenceTime> gpuCompositionDoneFence{FenceTime::NO_FENCE}; | 
|  | std::shared_ptr<FenceTime> displayPresentFence{FenceTime::NO_FENCE}; | 
|  | std::shared_ptr<FenceTime> releaseFence{FenceTime::NO_FENCE}; | 
|  | }; | 
|  |  | 
|  | struct CompositorTiming { | 
|  | nsecs_t deadline{0}; | 
|  | nsecs_t interval{16666667}; | 
|  | nsecs_t presentLatency{16666667}; | 
|  | }; | 
|  |  | 
|  | // A short history of frames that are synchronized between the consumer and | 
|  | // producer via deltas. | 
|  | class FrameEventHistory { | 
|  | public: | 
|  | virtual ~FrameEventHistory(); | 
|  |  | 
|  | FrameEvents* getFrame(uint64_t frameNumber); | 
|  | FrameEvents* getFrame(uint64_t frameNumber, size_t* iHint); | 
|  | void checkFencesForCompletion(); | 
|  | void dump(String8& outString) const; | 
|  |  | 
|  | static constexpr size_t MAX_FRAME_HISTORY = 8; | 
|  |  | 
|  | protected: | 
|  | std::array<FrameEvents, MAX_FRAME_HISTORY> mFrames; | 
|  |  | 
|  | CompositorTiming mCompositorTiming; | 
|  | }; | 
|  |  | 
|  |  | 
|  | // The producer's interface to FrameEventHistory | 
|  | 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); | 
|  | void applyDelta(const FrameEventHistoryDelta& delta); | 
|  |  | 
|  | void updateSignalTimes(); | 
|  |  | 
|  | 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}; | 
|  |  | 
|  | // The consumer updates it's timelines in Layer and SurfaceFlinger since | 
|  | // they can coordinate shared timelines better. The producer doesn't have | 
|  | // shared timelines though, so just let it own and update all of them. | 
|  | FenceTimeline mAcquireTimeline; | 
|  | FenceTimeline mGpuCompositionDoneTimeline; | 
|  | FenceTimeline mPresentTimeline; | 
|  | FenceTimeline mReleaseTimeline; | 
|  | }; | 
|  |  | 
|  |  | 
|  | // Used by the consumer to create a new frame event record that is | 
|  | // partially complete. | 
|  | struct NewFrameEventsEntry { | 
|  | uint64_t frameNumber{0}; | 
|  | nsecs_t postedTime{0}; | 
|  | nsecs_t requestedPresentTime{0}; | 
|  | std::shared_ptr<FenceTime> acquireFence{FenceTime::NO_FENCE}; | 
|  | }; | 
|  |  | 
|  |  | 
|  | // Used by the consumer to keep track of which fields it already sent to | 
|  | // the producer. | 
|  | class FrameEventDirtyFields { | 
|  | public: | 
|  | inline void reset() { mBitset.reset(); } | 
|  | inline bool anyDirty() const { return mBitset.any(); } | 
|  |  | 
|  | template <FrameEvent event> | 
|  | inline void setDirty() { | 
|  | constexpr size_t eventIndex = static_cast<size_t>(event); | 
|  | static_assert(eventIndex < FrameEvents::EVENT_COUNT, "Bad index."); | 
|  | mBitset.set(eventIndex); | 
|  | } | 
|  |  | 
|  | template <FrameEvent event> | 
|  | inline bool isDirty() const { | 
|  | constexpr size_t eventIndex = static_cast<size_t>(event); | 
|  | static_assert(eventIndex < FrameEvents::EVENT_COUNT, "Bad index."); | 
|  | return mBitset[eventIndex]; | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::bitset<FrameEvents::EVENT_COUNT> mBitset; | 
|  | }; | 
|  |  | 
|  |  | 
|  | // The consumer's interface to FrameEventHistory | 
|  | class ConsumerFrameEventHistory : public FrameEventHistory { | 
|  | public: | 
|  | ~ConsumerFrameEventHistory() override; | 
|  |  | 
|  | void onDisconnect(); | 
|  |  | 
|  | 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 CompositorTiming& compositorTiming); | 
|  | void addRelease(uint64_t frameNumber, nsecs_t dequeueReadyTime, | 
|  | std::shared_ptr<FenceTime>&& release); | 
|  |  | 
|  | void getAndResetDelta(FrameEventHistoryDelta* delta); | 
|  |  | 
|  | private: | 
|  | void getFrameDelta(FrameEventHistoryDelta* delta, | 
|  | const std::array<FrameEvents, MAX_FRAME_HISTORY>::iterator& frame); | 
|  |  | 
|  | std::array<FrameEventDirtyFields, MAX_FRAME_HISTORY> mFramesDirty; | 
|  |  | 
|  | size_t mQueueOffset{0}; | 
|  | size_t mCompositionOffset{0}; | 
|  | size_t mReleaseOffset{0}; | 
|  |  | 
|  | int mCurrentConnectId{0}; | 
|  | bool mProducerWantsEvents{false}; | 
|  | }; | 
|  |  | 
|  |  | 
|  | // A single frame update from the consumer to producer that can be sent | 
|  | // through Binder. | 
|  | // Although this may be sent multiple times for the same frame as new | 
|  | // timestamps are set, Fences only need to be sent once. | 
|  | class FrameEventsDelta : public Flattenable<FrameEventsDelta> { | 
|  | friend class ProducerFrameEventHistory; | 
|  | public: | 
|  | FrameEventsDelta() = default; | 
|  | FrameEventsDelta(size_t index, | 
|  | const FrameEvents& frameTimestamps, | 
|  | const FrameEventDirtyFields& dirtyFields); | 
|  |  | 
|  | // Movable. | 
|  | FrameEventsDelta(FrameEventsDelta&& src) = default; | 
|  | FrameEventsDelta& operator=(FrameEventsDelta&& src) = default; | 
|  | // Not copyable. | 
|  | FrameEventsDelta(const FrameEventsDelta& src) = delete; | 
|  | FrameEventsDelta& operator=(const FrameEventsDelta& src) = delete; | 
|  |  | 
|  | // Flattenable implementation | 
|  | size_t getFlattenedSize() const; | 
|  | size_t getFdCount() const; | 
|  | status_t flatten(void*& buffer, size_t& size, int*& fds, | 
|  | size_t& count) const; | 
|  | status_t unflatten(void const*& buffer, size_t& size, int const*& fds, | 
|  | size_t& count); | 
|  |  | 
|  | private: | 
|  | static constexpr size_t minFlattenedSize(); | 
|  |  | 
|  | size_t mIndex{0}; | 
|  | uint64_t mFrameNumber{0}; | 
|  |  | 
|  | bool mAddPostCompositeCalled{0}; | 
|  | bool mAddReleaseCalled{0}; | 
|  |  | 
|  | nsecs_t mPostedTime{FrameEvents::TIMESTAMP_PENDING}; | 
|  | nsecs_t mRequestedPresentTime{FrameEvents::TIMESTAMP_PENDING}; | 
|  | nsecs_t mLatchTime{FrameEvents::TIMESTAMP_PENDING}; | 
|  | nsecs_t mFirstRefreshStartTime{FrameEvents::TIMESTAMP_PENDING}; | 
|  | nsecs_t mLastRefreshStartTime{FrameEvents::TIMESTAMP_PENDING}; | 
|  | nsecs_t mDequeueReadyTime{FrameEvents::TIMESTAMP_PENDING}; | 
|  |  | 
|  | FenceTime::Snapshot mGpuCompositionDoneFence; | 
|  | FenceTime::Snapshot mDisplayPresentFence; | 
|  | FenceTime::Snapshot mReleaseFence; | 
|  |  | 
|  | // This is a static method with an auto return value so we can call | 
|  | // it without needing const and non-const versions. | 
|  | template <typename ThisT> | 
|  | static inline auto allFences(ThisT fed) -> | 
|  | std::array<decltype(&fed->mReleaseFence), 3> { | 
|  | return {{ | 
|  | &fed->mGpuCompositionDoneFence, &fed->mDisplayPresentFence, | 
|  | &fed->mReleaseFence | 
|  | }}; | 
|  | } | 
|  | }; | 
|  |  | 
|  |  | 
|  | // A collection of updates from consumer to producer that can be sent | 
|  | // through Binder. | 
|  | class FrameEventHistoryDelta | 
|  | : public Flattenable<FrameEventHistoryDelta> { | 
|  |  | 
|  | friend class ConsumerFrameEventHistory; | 
|  | friend class ProducerFrameEventHistory; | 
|  |  | 
|  | public: | 
|  | FrameEventHistoryDelta() = default; | 
|  |  | 
|  | // Movable. | 
|  | FrameEventHistoryDelta(FrameEventHistoryDelta&& src) = default; | 
|  | FrameEventHistoryDelta& operator=(FrameEventHistoryDelta&& src); | 
|  | // Not copyable. | 
|  | FrameEventHistoryDelta(const FrameEventHistoryDelta& src) = delete; | 
|  | FrameEventHistoryDelta& operator=( | 
|  | const FrameEventHistoryDelta& src) = delete; | 
|  |  | 
|  | // Flattenable implementation. | 
|  | size_t getFlattenedSize() const; | 
|  | size_t getFdCount() const; | 
|  | status_t flatten(void*& buffer, size_t& size, int*& fds, | 
|  | size_t& count) const; | 
|  | status_t unflatten(void const*& buffer, size_t& size, int const*& fds, | 
|  | size_t& count); | 
|  |  | 
|  | private: | 
|  | static constexpr size_t minFlattenedSize(); | 
|  |  | 
|  | std::vector<FrameEventsDelta> mDeltas; | 
|  | CompositorTiming mCompositorTiming; | 
|  | }; | 
|  |  | 
|  |  | 
|  | } // namespace android | 
|  | #endif |