| /* |
| * 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 = -2; |
| |
| 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 |