Cache frame event history producer-side.
* Producer maintains a recent history of frames.
* Producer only does a binder call if requested
informatiVon doesn't exist in the cache.
* Consumer sends fences to the producer, which
can be queried for timestamps without a
binder call.
Test: adb shell /data/nativetest/libgui_test/libgui_test
--gtest_filter=*GetFrameTimestamps*
Change-Id: I8a64579407cc2935f5c659462cb227b07ba27e43
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 8cf8b67..a523cd8 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -66,9 +66,9 @@
virtual void onFrameReplaced(const BufferItem& item) override;
virtual void onBuffersReleased() override;
virtual void onSidebandStreamChanged() override;
- virtual bool addAndGetFrameTimestamps(
+ virtual void addAndGetFrameTimestamps(
const NewFrameEventsEntry* newTimestamps,
- uint64_t frameNumber, FrameTimestamps* outTimestamps) override;
+ FrameEventHistoryDelta* outDelta) override;
private:
// mConsumerListener is a weak reference to the IConsumerListener. This is
// the raison d'etre of ProxyConsumerListener.
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 9cfb383..e6ee6c6 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -177,8 +177,7 @@
sp<Fence>* outFence, float outTransformMatrix[16]) override;
// See IGraphicBufferProducer::getFrameTimestamps
- virtual bool getFrameTimestamps(uint64_t frameNumber,
- FrameTimestamps* outTimestamps) override;
+ virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
// See IGraphicBufferProducer::getUniqueId
virtual status_t getUniqueId(uint64_t* outId) const override;
@@ -195,9 +194,8 @@
// BufferQueueCore::INVALID_BUFFER_SLOT otherwise
int getFreeSlotLocked() const;
- bool addAndGetFrameTimestamps(
- const NewFrameEventsEntry* newTimestamps,
- uint64_t frameNumber, FrameTimestamps* outTimestamps);
+ void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+ FrameEventHistoryDelta* outDelta);
// waitForFreeSlotThenRelock finds the oldest slot in the FREE state. It may
// block if there are no available slots and we are not in non-blocking
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index 6d3bd6c..5076597 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -23,47 +23,52 @@
#include <utils/Timers.h>
#include <array>
+#include <bitset>
+#include <vector>
namespace android {
struct FrameEvents;
+class FrameEventHistoryDelta;
class String8;
-enum class SupportableFrameTimestamps {
+enum class FrameEvent {
+ POSTED,
REQUESTED_PRESENT,
+ LATCH,
ACQUIRE,
- REFRESH_START,
- GL_COMPOSITION_DONE_TIME,
- DISPLAY_PRESENT_TIME,
- DISPLAY_RETIRE_TIME,
- RELEASE_TIME,
-};
-
-
-// The timestamps the consumer sends to the producer over binder.
-struct FrameTimestamps : public LightFlattenablePod<FrameTimestamps> {
- FrameTimestamps() = default;
- explicit FrameTimestamps(const FrameEvents& fences);
-
- uint64_t frameNumber{0};
- nsecs_t postedTime{0};
- nsecs_t requestedPresentTime{0};
- nsecs_t acquireTime{0};
- nsecs_t refreshStartTime{0};
- nsecs_t glCompositionDoneTime{0};
- nsecs_t displayPresentTime{0};
- nsecs_t displayRetireTime{0};
- nsecs_t releaseTime{0};
+ FIRST_REFRESH_START,
+ LAST_REFRESH_START,
+ GL_COMPOSITION_DONE,
+ DISPLAY_PRESENT,
+ DISPLAY_RETIRE,
+ RELEASE,
+ EVENT_COUNT, // Not an actual event.
};
// A collection of timestamps corresponding to a single frame.
struct FrameEvents {
+ 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 hasDisplayRetireInfo() const;
+ bool hasReleaseInfo() const;
+
void checkFencesForCompletion();
void dump(String8& outString) const;
+ static constexpr size_t EVENT_COUNT =
+ static_cast<size_t>(FrameEvent::EVENT_COUNT);
+ static_assert(EVENT_COUNT <= 32, "Event count sanity check failed.");
+
bool valid{false};
uint64_t frameNumber{0};
@@ -72,6 +77,7 @@
// a) we'll just never get them or b) they're not ready yet.
bool addPostCompositeCalled{false};
bool addRetireCalled{false};
+ bool addReleaseCalled{false};
nsecs_t postedTime{0};
nsecs_t requestedPresentTime{0};
@@ -93,6 +99,39 @@
};
+// 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;
+};
+
+
+// The producer's interface to FrameEventHistory
+class ProducerFrameEventHistory : public FrameEventHistory {
+public:
+ ~ProducerFrameEventHistory() override;
+
+ void updateAcquireFence(uint64_t frameNumber, sp<Fence> acquire);
+ void applyDelta(const FrameEventHistoryDelta& delta);
+
+private:
+ size_t mAcquireOffset{0};
+};
+
+
+// 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};
@@ -101,14 +140,38 @@
};
-class FrameEventHistory {
+// Used by the consumer to keep track of which fields it already sent to
+// the producer.
+class FrameEventDirtyFields {
public:
- FrameEvents* getFrame(uint64_t frameNumber);
- FrameEvents* getFrame(uint64_t frameNumber, size_t* iHint);
- void checkFencesForCompletion();
- void dump(String8& outString) const;
+ inline void reset() { mBitset.reset(); }
+ inline bool anyDirty() const { return mBitset.any(); }
- void addQueue(const NewFrameEventsEntry& newFrameEntry);
+ 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 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,
@@ -116,14 +179,96 @@
void addRetire(uint64_t frameNumber, sp<Fence> displayRetire);
void addRelease(uint64_t frameNumber, sp<Fence> release);
+ void getAndResetDelta(FrameEventHistoryDelta* delta);
+
private:
- static constexpr size_t MAX_FRAME_HISTORY = 8;
- std::array<FrameEvents, MAX_FRAME_HISTORY> mFrames;
+ std::array<FrameEventDirtyFields, MAX_FRAME_HISTORY> mFramesDirty;
size_t mQueueOffset{0};
size_t mCompositionOffset{0};
size_t mRetireOffset{0};
size_t mReleaseOffset{0};
};
+
+// 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);
+
+ // 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 size_t minFlattenedSize();
+
+ size_t mIndex{0};
+ uint64_t mFrameNumber{0};
+
+ bool mAddPostCompositeCalled{0};
+ bool mAddRetireCalled{0};
+ bool mAddReleaseCalled{0};
+
+ nsecs_t mPostedTime{0};
+ nsecs_t mRequestedPresentTime{0};
+ nsecs_t mLatchTime{0};
+ nsecs_t mFirstRefreshStartTime{0};
+ nsecs_t mLastRefreshStartTime{0};
+
+ sp<Fence> mAcquireFence{Fence::NO_FENCE};
+ sp<Fence> mGpuCompositionDoneFence{Fence::NO_FENCE};
+ sp<Fence> mDisplayPresentFence{Fence::NO_FENCE};
+ sp<Fence> mDisplayRetireFence{Fence::NO_FENCE};
+ sp<Fence> mReleaseFence{Fence::NO_FENCE};
+
+ // This is a static method with an auto return value so we can call
+ // it without needing const and non-const versions.
+ template <typename ThisType>
+ static inline auto allFences(ThisType fed) ->
+ std::array<decltype(&fed->mAcquireFence), 5> {
+ return {{
+ &fed->mAcquireFence, &fed->mGpuCompositionDoneFence,
+ &fed->mDisplayPresentFence, &fed->mDisplayRetireFence,
+ &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:
+ // 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 size_t minFlattenedSize();
+
+ std::vector<FrameEventsDelta> mDeltas;
+};
+
+
} // namespace android
#endif
diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h
index 8eab3c5..93dd4ac 100644
--- a/include/gui/IConsumerListener.h
+++ b/include/gui/IConsumerListener.h
@@ -82,13 +82,11 @@
// different stream.
virtual void onSidebandStreamChanged() = 0; /* Asynchronous */
- // Notifies the consumer of any new producer-side events and then queries
- // the consumer timestamps
- virtual bool addAndGetFrameTimestamps(
+ // Notifies the consumer of any new producer-side timestamps and
+ // returns the combined frame history that hasn't already been retrieved.
+ virtual void addAndGetFrameTimestamps(
const NewFrameEventsEntry* /*newTimestamps*/,
- uint64_t /*frameNumber*/, FrameTimestamps* /*outTimestamps*/) {
- return false;
- }
+ FrameEventHistoryDelta* /*outDelta*/) {}
};
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 493143a..612a902 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -588,13 +588,8 @@
virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
sp<Fence>* outFence, float outTransformMatrix[16]) = 0;
- // Attempts to retrieve timestamp information for the given frame number.
- // If information for the given frame number is not found, returns false.
- // Returns true otherwise.
- //
- // If a fence has not yet signaled the timestamp returned will be 0;
- virtual bool getFrameTimestamps(uint64_t /*frameNumber*/,
- FrameTimestamps* /*outTimestamps*/) { return false; }
+ // Gets the frame events that haven't already been retrieved.
+ virtual void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) {}
// Returns a unique id for this BufferQueue
virtual status_t getUniqueId(uint64_t* outId) const = 0;
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index bc36970..824e5c4 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -45,7 +45,7 @@
class IDisplayEventConnection;
class IMemoryHeap;
class Rect;
-enum class SupportableFrameTimestamps;
+enum class FrameEvent;
/*
* This class defines the Binder IPC interface for accessing various
@@ -118,7 +118,7 @@
/* Returns the frame timestamps supported by SurfaceFlinger.
*/
virtual status_t getSupportedFrameTimestamps(
- std::vector<SupportableFrameTimestamps>* outSupported) const = 0;
+ std::vector<FrameEvent>* outSupported) const = 0;
/* set display power mode. depending on the mode, it can either trigger
* screen on, off or low power mode and wait for it to complete.
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index aa5657f..c12d452 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -388,6 +388,9 @@
mutable bool mQueriedSupportedTimestamps;
mutable bool mFrameTimestampsSupportsPresent;
mutable bool mFrameTimestampsSupportsRetire;
+
+ // A cached copy of the FrameEventHistory maintained by the consumer.
+ ProducerFrameEventHistory mFrameEventHistory;
};
namespace view {