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/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 6d4335e..f76a282 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -61,15 +61,13 @@
}
}
-bool BufferQueue::ProxyConsumerListener::addAndGetFrameTimestamps(
+void BufferQueue::ProxyConsumerListener::addAndGetFrameTimestamps(
const NewFrameEventsEntry* newTimestamps,
- uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+ FrameEventHistoryDelta* outDelta) {
sp<ConsumerListener> listener(mConsumerListener.promote());
- if (listener == nullptr) {
- return false;
+ if (listener != nullptr) {
+ listener->addAndGetFrameTimestamps(newTimestamps, outDelta);
}
- return listener->addAndGetFrameTimestamps(
- newTimestamps, frameNumber, outTimestamps);
}
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 6bd1cfd..e27fd7a 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -975,7 +975,7 @@
requestedPresentTimestamp,
acquireFence
};
- addAndGetFrameTimestamps(&newFrameEventsEntry, 0, nullptr);
+ addAndGetFrameTimestamps(&newFrameEventsEntry, nullptr);
return NO_ERROR;
}
@@ -1464,16 +1464,15 @@
return NO_ERROR;
}
-bool BufferQueueProducer::getFrameTimestamps(
- uint64_t frameNumber, FrameTimestamps* outTimestamps) {
- return addAndGetFrameTimestamps(nullptr, frameNumber, outTimestamps);
+void BufferQueueProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
+ addAndGetFrameTimestamps(nullptr, outDelta);
}
-bool BufferQueueProducer::addAndGetFrameTimestamps(
+void BufferQueueProducer::addAndGetFrameTimestamps(
const NewFrameEventsEntry* newTimestamps,
- uint64_t frameNumber, FrameTimestamps* outTimestamps) {
- if (newTimestamps == nullptr && outTimestamps == nullptr) {
- return false;
+ FrameEventHistoryDelta* outDelta) {
+ if (newTimestamps == nullptr && outDelta == nullptr) {
+ return;
}
ATRACE_CALL();
@@ -1484,10 +1483,8 @@
listener = mCore->mConsumerListener;
}
if (listener != NULL) {
- return listener->addAndGetFrameTimestamps(
- newTimestamps, frameNumber, outTimestamps);
+ listener->addAndGetFrameTimestamps(newTimestamps, outDelta);
}
- return false;
}
void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index a919911..4b98cff 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -21,6 +21,7 @@
#include <algorithm>
#include <limits>
+#include <numeric>
namespace android {
@@ -29,25 +30,56 @@
}
// ============================================================================
-// FrameTimestamps
-// ============================================================================
-
-FrameTimestamps::FrameTimestamps(const FrameEvents& events) :
- frameNumber(events.frameNumber),
- postedTime(events.postedTime),
- requestedPresentTime(events.requestedPresentTime),
- acquireTime(events.acquireTime),
- refreshStartTime(events.firstRefreshStartTime),
- glCompositionDoneTime(events.gpuCompositionDoneTime),
- displayPresentTime(events.displayPresentTime),
- displayRetireTime(events.displayRetireTime),
- releaseTime(events.releaseTime) {}
-
-
-// ============================================================================
// FrameEvents
// ============================================================================
+bool FrameEvents::hasPostedInfo() const {
+ return isValidTimestamp(postedTime);
+}
+
+bool FrameEvents::hasRequestedPresentInfo() const {
+ return isValidTimestamp(requestedPresentTime);
+}
+
+bool FrameEvents::hasLatchInfo() const {
+ return isValidTimestamp(latchTime);
+}
+
+bool FrameEvents::hasFirstRefreshStartInfo() const {
+ return isValidTimestamp(firstRefreshStartTime);
+}
+
+bool FrameEvents::hasLastRefreshStartInfo() const {
+ // The last refresh start time may continue to update until a new frame
+ // is latched. We know we have the final value once the release or retire
+ // info is set. See ConsumerFrameEventHistory::addRetire/Release.
+ return addRetireCalled || addReleaseCalled;
+}
+
+bool FrameEvents::hasAcquireInfo() const {
+ return isValidTimestamp(acquireTime) || acquireFence->isValid();
+}
+
+bool FrameEvents::hasGpuCompositionDoneInfo() const {
+ // We may not get a gpuCompositionDone in addPostComposite if
+ // client/gles compositing isn't needed.
+ return addPostCompositeCalled;
+}
+
+bool FrameEvents::hasDisplayPresentInfo() const {
+ // We may not get a displayPresent in addPostComposite for HWC1.
+ return addPostCompositeCalled;
+}
+
+bool FrameEvents::hasDisplayRetireInfo() const {
+ // We may not get a displayRetire in addRetire for HWC2.
+ return addRetireCalled;
+}
+
+bool FrameEvents::hasReleaseInfo() const {
+ return addReleaseCalled;
+}
+
static void checkFenceForCompletion(sp<Fence>* fence, nsecs_t* dstTime) {
if ((*fence)->isValid()) {
nsecs_t time = (*fence)->getSignalTime();
@@ -156,6 +188,7 @@
} // namespace
+FrameEventHistory::~FrameEventHistory() = default;
FrameEvents* FrameEventHistory::getFrame(uint64_t frameNumber) {
auto frame = std::find_if(
@@ -209,82 +242,407 @@
}
}
-void FrameEventHistory::addQueue(const NewFrameEventsEntry& newFrameEntry) {
- // Overwrite all fields of the frame with default values unless set here.
- FrameEvents newTimestamps;
- newTimestamps.frameNumber = newFrameEntry.frameNumber;
- newTimestamps.postedTime = newFrameEntry.postedTime;
- newTimestamps.requestedPresentTime = newFrameEntry.requestedPresentTime;
- newTimestamps.acquireFence = newFrameEntry.acquireFence;
- newTimestamps.valid = true;
- mFrames[mQueueOffset] = newTimestamps;
- mQueueOffset = mQueueOffset + 1;
- if (mQueueOffset >= mFrames.size()) {
- mQueueOffset = 0;
- }
-}
+// ============================================================================
+// ProducerFrameEventHistory
+// ============================================================================
-void FrameEventHistory::addLatch(uint64_t frameNumber, nsecs_t latchTime) {
- FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
+ProducerFrameEventHistory::~ProducerFrameEventHistory() = default;
+
+void ProducerFrameEventHistory::updateAcquireFence(
+ uint64_t frameNumber, sp<Fence> acquire) {
+ FrameEvents* frame = getFrame(frameNumber, &mAcquireOffset);
if (frame == nullptr) {
- ALOGE("FrameEventHistory::addLatch: Did not find frame.");
- return;
- }
- frame->latchTime = latchTime;
- return;
-}
-
-void FrameEventHistory::addPreComposition(
- uint64_t frameNumber, nsecs_t refreshStartTime) {
- FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
- if (frame == nullptr) {
- ALOGE("FrameEventHistory::addPreComposition: Did not find frame.");
- return;
- }
- frame->lastRefreshStartTime = refreshStartTime;
- if (!isValidTimestamp(frame->firstRefreshStartTime)) {
- frame->firstRefreshStartTime = refreshStartTime;
- }
-}
-
-void FrameEventHistory::addPostComposition(uint64_t frameNumber,
- sp<Fence> gpuCompositionDone, sp<Fence> displayPresent) {
- FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
- if (frame == nullptr) {
- ALOGE("FrameEventHistory::addPostComposition: Did not find frame.");
+ ALOGE("ProducerFrameEventHistory::updateAcquireFence: "
+ "Did not find frame.");
return;
}
- // Only get GPU and present info for the first composite.
- if (!frame->addPostCompositeCalled) {
- frame->addPostCompositeCalled = true;
- frame->gpuCompositionDoneFence = gpuCompositionDone;
- if (!frame->displayPresentFence->isValid()) {
- frame->displayPresentFence = displayPresent;
+ if (acquire->isValid()) {
+ frame->acquireFence = acquire;
+ } else {
+ // If there isn't an acquire fence, assume that buffer was
+ // ready for the consumer when posted.
+ frame->acquireTime = frame->postedTime;
+ }
+}
+
+static void applyFenceDelta(sp<Fence>* dst, const sp<Fence>& src) {
+ if (src->isValid()) {
+ if ((*dst)->isValid()) {
+ ALOGE("applyFenceDelta: Unexpected fence.");
+ }
+ *dst = src;
+ }
+}
+
+void ProducerFrameEventHistory::applyDelta(
+ const FrameEventHistoryDelta& delta) {
+ for (auto& d : delta.mDeltas) {
+ // Avoid out-of-bounds access.
+ if (d.mIndex >= mFrames.size()) {
+ ALOGE("ProducerFrameEventHistory::applyDelta: Bad index.");
+ return;
+ }
+
+ FrameEvents& frame = mFrames[d.mIndex];
+
+ frame.addPostCompositeCalled = d.mAddPostCompositeCalled != 0;
+ frame.addRetireCalled = d.mAddRetireCalled != 0;
+ frame.addReleaseCalled = d.mAddReleaseCalled != 0;
+
+ frame.postedTime = d.mPostedTime;
+ frame.requestedPresentTime = d.mRequestedPresentTime;
+ frame.latchTime = d.mLatchTime;
+ frame.firstRefreshStartTime = d.mFirstRefreshStartTime;
+ frame.lastRefreshStartTime = d.mLastRefreshStartTime;
+
+ if (frame.frameNumber == d.mFrameNumber) {
+ // Existing frame. Merge.
+ // Consumer never sends timestamps of fences, only the fences
+ // themselves, so we never need to update the fence timestamps here.
+ applyFenceDelta(&frame.acquireFence, d.mAcquireFence);
+ applyFenceDelta(
+ &frame.gpuCompositionDoneFence, d.mGpuCompositionDoneFence);
+ applyFenceDelta(&frame.displayPresentFence, d.mDisplayPresentFence);
+ applyFenceDelta(&frame.displayRetireFence, d.mDisplayRetireFence);
+ applyFenceDelta(&frame.releaseFence, d.mReleaseFence);
+ } else {
+ // New frame. Overwrite.
+ frame.frameNumber = d.mFrameNumber;
+
+ frame.gpuCompositionDoneFence = d.mGpuCompositionDoneFence;
+ frame.displayPresentFence = d.mDisplayPresentFence;
+ frame.displayRetireFence = d.mDisplayRetireFence;
+ frame.releaseFence = d.mReleaseFence;
+
+ // Set aquire fence and time at this point.
+ frame.acquireTime = 0;
+ frame.acquireFence = d.mAcquireFence;
+
+ // Reset fence-related timestamps
+ frame.gpuCompositionDoneTime = 0;
+ frame.displayPresentTime = 0;
+ frame.displayRetireTime = 0;
+ frame.releaseTime = 0;
+
+ // The consumer only sends valid frames.
+ frame.valid = true;
}
}
}
-void FrameEventHistory::addRetire(
+
+// ============================================================================
+// ConsumerFrameEventHistory
+// ============================================================================
+
+ConsumerFrameEventHistory::~ConsumerFrameEventHistory() = default;
+
+void ConsumerFrameEventHistory::addQueue(const NewFrameEventsEntry& newEntry) {
+ // Overwrite all fields of the frame with default values unless set here.
+ FrameEvents newTimestamps;
+ newTimestamps.frameNumber = newEntry.frameNumber;
+ newTimestamps.postedTime = newEntry.postedTime;
+ newTimestamps.requestedPresentTime = newEntry.requestedPresentTime;
+ newTimestamps.acquireFence = newEntry.acquireFence;
+ newTimestamps.valid = true;
+ mFrames[mQueueOffset] = newTimestamps;
+ mFramesDirty[mQueueOffset].setDirty<FrameEvent::POSTED>();
+ mFramesDirty[mQueueOffset].setDirty<FrameEvent::ACQUIRE>();
+
+ mQueueOffset = (mQueueOffset + 1) % mFrames.size();
+}
+
+void ConsumerFrameEventHistory::addLatch(
+ uint64_t frameNumber, nsecs_t latchTime) {
+ FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
+ if (frame == nullptr) {
+ ALOGE("ConsumerFrameEventHistory::addLatch: Did not find frame.");
+ return;
+ }
+ frame->latchTime = latchTime;
+ mFramesDirty[mCompositionOffset].setDirty<FrameEvent::LATCH>();
+}
+
+void ConsumerFrameEventHistory::addPreComposition(
+ uint64_t frameNumber, nsecs_t refreshStartTime) {
+ FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
+ if (frame == nullptr) {
+ ALOGE("ConsumerFrameEventHistory::addPreComposition: "
+ "Did not find frame.");
+ return;
+ }
+ frame->lastRefreshStartTime = refreshStartTime;
+ mFramesDirty[mCompositionOffset].setDirty<FrameEvent::LAST_REFRESH_START>();
+ if (!isValidTimestamp(frame->firstRefreshStartTime)) {
+ frame->firstRefreshStartTime = refreshStartTime;
+ mFramesDirty[mCompositionOffset].setDirty<FrameEvent::FIRST_REFRESH_START>();
+ }
+}
+
+void ConsumerFrameEventHistory::addPostComposition(uint64_t frameNumber,
+ sp<Fence> gpuCompositionDone, sp<Fence> displayPresent) {
+ FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
+ if (frame == nullptr) {
+ ALOGE("ConsumerFrameEventHistory::addPostComposition: "
+ "Did not find frame.");
+ return;
+ }
+ // Only get GPU and present info for the first composite.
+ if (!frame->addPostCompositeCalled) {
+ frame->addPostCompositeCalled = true;
+ frame->gpuCompositionDoneFence = gpuCompositionDone;
+ mFramesDirty[mCompositionOffset].setDirty<FrameEvent::GL_COMPOSITION_DONE>();
+ if (!frame->displayPresentFence->isValid()) {
+ frame->displayPresentFence = displayPresent;
+ mFramesDirty[mCompositionOffset].setDirty<FrameEvent::DISPLAY_PRESENT>();
+ }
+ }
+}
+
+void ConsumerFrameEventHistory::addRetire(
uint64_t frameNumber, sp<Fence> displayRetire) {
FrameEvents* frame = getFrame(frameNumber, &mRetireOffset);
if (frame == nullptr) {
- ALOGE("FrameEventHistory::addRetire: Did not find frame.");
+ ALOGE("ConsumerFrameEventHistory::addRetire: Did not find frame.");
return;
}
frame->addRetireCalled = true;
frame->displayRetireFence = displayRetire;
+ mFramesDirty[mRetireOffset].setDirty<FrameEvent::DISPLAY_RETIRE>();
}
-void FrameEventHistory::addRelease(
+void ConsumerFrameEventHistory::addRelease(
uint64_t frameNumber, sp<Fence> release) {
FrameEvents* frame = getFrame(frameNumber, &mReleaseOffset);
if (frame == nullptr) {
- ALOGE("FrameEventHistory::addRelease: Did not find frame.");
+ ALOGE("ConsumerFrameEventHistory::addRelease: Did not find frame.");
return;
}
+ frame->addReleaseCalled = true;
frame->releaseFence = release;
+ mFramesDirty[mReleaseOffset].setDirty<FrameEvent::RELEASE>();
}
+void ConsumerFrameEventHistory::getAndResetDelta(
+ FrameEventHistoryDelta* delta) {
+ delta->mDeltas.reserve(mFramesDirty.size());
+ for (size_t i = 0; i < mFramesDirty.size(); i++) {
+ if (mFramesDirty[i].anyDirty()) {
+ delta->mDeltas.push_back(
+ FrameEventsDelta(i, mFrames[i], mFramesDirty[i]));
+ mFramesDirty[i].reset();
+ }
+ }
+}
+
+
+// ============================================================================
+// FrameEventsDelta
+// ============================================================================
+
+FrameEventsDelta::FrameEventsDelta(
+ size_t index,
+ const FrameEvents& frameTimestamps,
+ const FrameEventDirtyFields& dirtyFields)
+ : mIndex(index),
+ mFrameNumber(frameTimestamps.frameNumber),
+ mAddPostCompositeCalled(frameTimestamps.addPostCompositeCalled),
+ mAddRetireCalled(frameTimestamps.addRetireCalled),
+ mAddReleaseCalled(frameTimestamps.addReleaseCalled),
+ mPostedTime(frameTimestamps.postedTime),
+ mRequestedPresentTime(frameTimestamps.requestedPresentTime),
+ mLatchTime(frameTimestamps.latchTime),
+ mFirstRefreshStartTime(frameTimestamps.firstRefreshStartTime),
+ mLastRefreshStartTime(frameTimestamps.lastRefreshStartTime) {
+ mAcquireFence = dirtyFields.isDirty<FrameEvent::ACQUIRE>() ?
+ frameTimestamps.acquireFence : Fence::NO_FENCE;
+ mGpuCompositionDoneFence =
+ dirtyFields.isDirty<FrameEvent::GL_COMPOSITION_DONE>() ?
+ frameTimestamps.gpuCompositionDoneFence : Fence::NO_FENCE;
+ mDisplayPresentFence = dirtyFields.isDirty<FrameEvent::DISPLAY_PRESENT>() ?
+ frameTimestamps.displayPresentFence : Fence::NO_FENCE;
+ mDisplayRetireFence = dirtyFields.isDirty<FrameEvent::DISPLAY_RETIRE>() ?
+ frameTimestamps.displayRetireFence : Fence::NO_FENCE;
+ mReleaseFence = dirtyFields.isDirty<FrameEvent::RELEASE>() ?
+ frameTimestamps.releaseFence : Fence::NO_FENCE;
+}
+
+size_t FrameEventsDelta::minFlattenedSize() {
+ constexpr size_t min =
+ sizeof(FrameEventsDelta::mFrameNumber) +
+ sizeof(uint8_t) + // mIndex
+ sizeof(uint8_t) + // mAddPostCompositeCalled
+ sizeof(uint8_t) + // mAddRetireCalled
+ sizeof(uint8_t) + // mAddReleaseCalled
+ sizeof(FrameEventsDelta::mPostedTime) +
+ sizeof(FrameEventsDelta::mRequestedPresentTime) +
+ sizeof(FrameEventsDelta::mLatchTime) +
+ sizeof(FrameEventsDelta::mFirstRefreshStartTime) +
+ sizeof(FrameEventsDelta::mLastRefreshStartTime);
+ return min;
+}
+
+// Flattenable implementation
+size_t FrameEventsDelta::getFlattenedSize() const {
+ auto fences = allFences(this);
+ return minFlattenedSize() +
+ std::accumulate(fences.begin(), fences.end(), size_t(0),
+ [](size_t a, const sp<Fence>* fence) {
+ return a + (*fence)->getFlattenedSize();
+ });
+}
+
+size_t FrameEventsDelta::getFdCount() const {
+ auto fences = allFences(this);
+ return std::accumulate(fences.begin(), fences.end(), size_t(0),
+ [](size_t a, const sp<Fence>* fence) {
+ return a + (*fence)->getFdCount();
+ });
+}
+
+status_t FrameEventsDelta::flatten(void*& buffer, size_t& size, int*& fds,
+ size_t& count) const {
+ if (size < getFlattenedSize() || count < getFdCount()) {
+ return NO_MEMORY;
+ }
+
+ if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY ||
+ mIndex > std::numeric_limits<uint8_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ FlattenableUtils::write(buffer, size, mFrameNumber);
+
+ // These are static_cast to uint8_t for alignment.
+ FlattenableUtils::write(buffer, size, static_cast<uint8_t>(mIndex));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(mAddPostCompositeCalled));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(mAddRetireCalled));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(mAddReleaseCalled));
+
+ FlattenableUtils::write(buffer, size, mPostedTime);
+ FlattenableUtils::write(buffer, size, mRequestedPresentTime);
+ FlattenableUtils::write(buffer, size, mLatchTime);
+ FlattenableUtils::write(buffer, size, mFirstRefreshStartTime);
+ FlattenableUtils::write(buffer, size, mLastRefreshStartTime);
+
+ // Fences
+ for (auto fence : allFences(this)) {
+ status_t status = (*fence)->flatten(buffer, size, fds, count);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t FrameEventsDelta::unflatten(void const*& buffer, size_t& size,
+ int const*& fds, size_t& count) {
+ if (size < minFlattenedSize()) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::read(buffer, size, mFrameNumber);
+
+ // These were written as uint8_t for alignment.
+ uint8_t temp = 0;
+ FlattenableUtils::read(buffer, size, temp);
+ mIndex = temp;
+ if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ FlattenableUtils::read(buffer, size, temp);
+ mAddPostCompositeCalled = static_cast<bool>(temp);
+ FlattenableUtils::read(buffer, size, temp);
+ mAddRetireCalled = static_cast<bool>(temp);
+ FlattenableUtils::read(buffer, size, temp);
+ mAddReleaseCalled = static_cast<bool>(temp);
+
+ FlattenableUtils::read(buffer, size, mPostedTime);
+ FlattenableUtils::read(buffer, size, mRequestedPresentTime);
+ FlattenableUtils::read(buffer, size, mLatchTime);
+ FlattenableUtils::read(buffer, size, mFirstRefreshStartTime);
+ FlattenableUtils::read(buffer, size, mLastRefreshStartTime);
+
+ // Fences
+ for (auto fence : allFences(this)) {
+ *fence = new Fence;
+ status_t status = (*fence)->unflatten(buffer, size, fds, count);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+
+// ============================================================================
+// FrameEventHistoryDelta
+// ============================================================================
+
+size_t FrameEventHistoryDelta::minFlattenedSize() {
+ return sizeof(uint32_t);
+}
+
+size_t FrameEventHistoryDelta::getFlattenedSize() const {
+ return minFlattenedSize() +
+ std::accumulate(mDeltas.begin(), mDeltas.end(), size_t(0),
+ [](size_t a, const FrameEventsDelta& delta) {
+ return a + delta.getFlattenedSize();
+ });
+}
+
+size_t FrameEventHistoryDelta::getFdCount() const {
+ return std::accumulate(mDeltas.begin(), mDeltas.end(), size_t(0),
+ [](size_t a, const FrameEventsDelta& delta) {
+ return a + delta.getFdCount();
+ });
+}
+
+status_t FrameEventHistoryDelta::flatten(
+ void*& buffer, size_t& size, int*& fds, size_t& count) const {
+ if (mDeltas.size() > FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ if (size < getFlattenedSize()) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint32_t>(mDeltas.size()));
+ for (auto& d : mDeltas) {
+ status_t status = d.flatten(buffer, size, fds, count);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t FrameEventHistoryDelta::unflatten(
+ void const*& buffer, size_t& size, int const*& fds, size_t& count) {
+ if (size < minFlattenedSize()) {
+ return NO_MEMORY;
+ }
+
+ uint32_t deltaCount = 0;
+ FlattenableUtils::read(buffer, size, deltaCount);
+ if (deltaCount > FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ mDeltas.resize(deltaCount);
+ for (auto& d : mDeltas) {
+ status_t status = d.unflatten(buffer, size, fds, count);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+
} // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index a4de7eb..bed7d53 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -429,40 +429,24 @@
return result;
}
- virtual bool getFrameTimestamps(uint64_t frameNumber,
- FrameTimestamps* outTimestamps) {
+ virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) {
Parcel data, reply;
status_t result = data.writeInterfaceToken(
IGraphicBufferProducer::getInterfaceDescriptor());
if (result != NO_ERROR) {
- ALOGE("getFrameTimestamps failed to write token: %d", result);
- return false;
- }
- result = data.writeUint64(frameNumber);
- if (result != NO_ERROR) {
- ALOGE("getFrameTimestamps failed to write: %d", result);
- return false;
+ ALOGE("IGBP::getFrameTimestamps failed to write token: %d", result);
+ return;
}
result = remote()->transact(GET_FRAME_TIMESTAMPS, data, &reply);
if (result != NO_ERROR) {
- ALOGE("getFrameTimestamps failed to transact: %d", result);
- return false;
+ ALOGE("IGBP::getFrameTimestamps failed to transact: %d", result);
+ return;
}
- bool found = false;
- result = reply.readBool(&found);
+ result = reply.read(*outDelta);
if (result != NO_ERROR) {
- ALOGE("getFrameTimestamps failed to read: %d", result);
- return false;
+ ALOGE("IGBP::getFrameTimestamps failed to read timestamps: %d",
+ result);
}
- if (found) {
- result = reply.read(*outTimestamps);
- if (result != NO_ERROR) {
- ALOGE("getFrameTimestamps failed to read timestamps: %d",
- result);
- return false;
- }
- }
- return found;
}
virtual status_t getUniqueId(uint64_t* outId) const {
@@ -722,26 +706,14 @@
}
case GET_FRAME_TIMESTAMPS: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
- uint64_t frameNumber = 0;
- status_t result = data.readUint64(&frameNumber);
+ FrameEventHistoryDelta frameTimestamps;
+ getFrameTimestamps(&frameTimestamps);
+ status_t result = reply->write(frameTimestamps);
if (result != NO_ERROR) {
- ALOGE("onTransact failed to read: %d", result);
+ ALOGE("BnGBP::GET_FRAME_TIMESTAMPS failed to write buffer: %d",
+ result);
return result;
}
- FrameTimestamps timestamps;
- bool found = getFrameTimestamps(frameNumber, ×tamps);
- result = reply->writeBool(found);
- if (result != NO_ERROR) {
- ALOGE("onTransact failed to write: %d", result);
- return result;
- }
- if (found) {
- result = reply->write(timestamps);
- if (result != NO_ERROR) {
- ALOGE("onTransact failed to write timestamps: %d", result);
- return result;
- }
- }
return NO_ERROR;
}
case GET_UNIQUE_ID: {
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index b5fe266..fa2f59a 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -159,7 +159,7 @@
}
virtual status_t getSupportedFrameTimestamps(
- std::vector<SupportableFrameTimestamps>* outSupported) const {
+ std::vector<FrameEvent>* outSupported) const {
if (!outSupported) {
return UNEXPECTED_NULL;
}
@@ -197,7 +197,7 @@
outSupported->reserve(supported.size());
for (int32_t s : supported) {
- outSupported->push_back(static_cast<SupportableFrameTimestamps>(s));
+ outSupported->push_back(static_cast<FrameEvent>(s));
}
return NO_ERROR;
}
@@ -566,7 +566,7 @@
}
case GET_SUPPORTED_FRAME_TIMESTAMPS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- std::vector<SupportableFrameTimestamps> supportedTimestamps;
+ std::vector<FrameEvent> supportedTimestamps;
status_t result = getSupportedFrameTimestamps(&supportedTimestamps);
status_t err = reply->writeInt32(result);
if (err != NO_ERROR) {
@@ -578,7 +578,7 @@
std::vector<int32_t> supported;
supported.reserve(supportedTimestamps.size());
- for (SupportableFrameTimestamps s : supportedTimestamps) {
+ for (FrameEvent s : supportedTimestamps) {
supported.push_back(static_cast<int32_t>(s));
}
return reply->writeInt32Vector(supported);
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 5203cce..c29101e 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -145,47 +145,61 @@
nsecs_t* outReleaseTime) {
ATRACE_CALL();
- {
- Mutex::Autolock lock(mMutex);
+ Mutex::Autolock lock(mMutex);
- // Verify the requested timestamps are supported.
- querySupportedTimestampsLocked();
- if (outDisplayPresentTime != nullptr && !mFrameTimestampsSupportsPresent) {
- return BAD_VALUE;
- }
- if (outDisplayRetireTime != nullptr && !mFrameTimestampsSupportsRetire) {
- return BAD_VALUE;
- }
+ // Verify the requested timestamps are supported.
+ querySupportedTimestampsLocked();
+ if (outDisplayPresentTime != nullptr && !mFrameTimestampsSupportsPresent) {
+ return BAD_VALUE;
+ }
+ if (outDisplayRetireTime != nullptr && !mFrameTimestampsSupportsRetire) {
+ return BAD_VALUE;
}
- FrameTimestamps timestamps;
- bool found = mGraphicBufferProducer->getFrameTimestamps(frameNumber,
- ×tamps);
+ FrameEvents* events = mFrameEventHistory.getFrame(frameNumber);
- if (!found) {
+ // Update our cache of events if the requested events are not available.
+ if (events == nullptr ||
+ (outRequestedPresentTime && !events->hasRequestedPresentInfo()) ||
+ (outAcquireTime && !events->hasAcquireInfo()) ||
+ (outRefreshStartTime && !events->hasFirstRefreshStartInfo()) ||
+ (outGlCompositionDoneTime && !events->hasGpuCompositionDoneInfo()) ||
+ (outDisplayPresentTime && !events->hasDisplayPresentInfo()) ||
+ (outDisplayRetireTime && !events->hasDisplayRetireInfo()) ||
+ (outReleaseTime && !events->hasReleaseInfo())) {
+ FrameEventHistoryDelta delta;
+ mGraphicBufferProducer->getFrameTimestamps(&delta);
+ mFrameEventHistory.applyDelta(delta);
+ events = mFrameEventHistory.getFrame(frameNumber);
+ }
+
+ // A record for the requested frame does not exist.
+ if (events == nullptr) {
return NAME_NOT_FOUND;
}
+ events->checkFencesForCompletion();
+
if (outRequestedPresentTime) {
- *outRequestedPresentTime = timestamps.requestedPresentTime;
+ *outRequestedPresentTime = events->requestedPresentTime;
}
if (outAcquireTime) {
- *outAcquireTime = timestamps.acquireTime;
+ *outAcquireTime = events->acquireTime;
}
if (outRefreshStartTime) {
- *outRefreshStartTime = timestamps.refreshStartTime;
+ *outRefreshStartTime = events->firstRefreshStartTime;
}
if (outGlCompositionDoneTime) {
- *outGlCompositionDoneTime = timestamps.glCompositionDoneTime;
+ *outGlCompositionDoneTime = events->gpuCompositionDoneTime;
}
if (outDisplayPresentTime) {
- *outDisplayPresentTime = timestamps.displayPresentTime;
+ *outDisplayPresentTime = events->displayPresentTime;
}
if (outDisplayRetireTime) {
- *outDisplayRetireTime = timestamps.displayRetireTime;
+ *outDisplayRetireTime = events->displayRetireTime;
}
if (outReleaseTime) {
- *outReleaseTime = timestamps.releaseTime;
+ *outReleaseTime = events->releaseTime;
}
return NO_ERROR;
@@ -564,7 +578,7 @@
}
mQueriedSupportedTimestamps = true;
- std::vector<SupportableFrameTimestamps> supportedFrameTimestamps;
+ std::vector<FrameEvent> supportedFrameTimestamps;
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
status_t err = composer->getSupportedFrameTimestamps(
&supportedFrameTimestamps);
@@ -574,9 +588,9 @@
}
for (auto sft : supportedFrameTimestamps) {
- if (sft == SupportableFrameTimestamps::DISPLAY_PRESENT_TIME) {
+ if (sft == FrameEvent::DISPLAY_PRESENT) {
mFrameTimestampsSupportsPresent = true;
- } else if (sft == SupportableFrameTimestamps::DISPLAY_RETIRE_TIME) {
+ } else if (sft == FrameEvent::DISPLAY_RETIRE) {
mFrameTimestampsSupportsRetire = true;
}
}