Track frame events incrementally and per layer.
* Replaces FenceTracker, which was owned by SurfaceFlinger,
with FrameEventHistory, which is owned by Layer.
* Updates FrameEventHistory as events occur.
* Changes SurfaceFlinger flag "--fences" to
"--frame-events".
Test: adb shell /data/nativetest/libgui_test/libgui_test
--gtest_filter=*GetFrameTimestamps*
Change-Id: I868c2ef93964656d7e41848243433499e7f45fe7
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index f24f135..8cf8b67 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -66,8 +66,9 @@
virtual void onFrameReplaced(const BufferItem& item) override;
virtual void onBuffersReleased() override;
virtual void onSidebandStreamChanged() override;
- virtual bool getFrameTimestamps(uint64_t frameNumber,
- FrameTimestamps* outTimestamps) const override;
+ virtual bool addAndGetFrameTimestamps(
+ const NewFrameEventsEntry* newTimestamps,
+ uint64_t frameNumber, FrameTimestamps* outTimestamps) 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 65dea0d..9cfb383 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -178,7 +178,7 @@
// See IGraphicBufferProducer::getFrameTimestamps
virtual bool getFrameTimestamps(uint64_t frameNumber,
- FrameTimestamps* outTimestamps) const override;
+ FrameTimestamps* outTimestamps) override;
// See IGraphicBufferProducer::getUniqueId
virtual status_t getUniqueId(uint64_t* outId) const override;
@@ -195,6 +195,10 @@
// BufferQueueCore::INVALID_BUFFER_SLOT otherwise
int getFreeSlotLocked() const;
+ bool addAndGetFrameTimestamps(
+ const NewFrameEventsEntry* newTimestamps,
+ uint64_t frameNumber, FrameTimestamps* outTimestamps);
+
// 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
// mode (producer and consumer controlled by the application). If it blocks,
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index b8bfcd7..6d3bd6c 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -17,11 +17,20 @@
#ifndef ANDROID_GUI_FRAMETIMESTAMPS_H
#define ANDROID_GUI_FRAMETIMESTAMPS_H
-#include <utils/Timers.h>
+#include <ui/Fence.h>
#include <utils/Flattenable.h>
+#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
+
+#include <array>
namespace android {
+
+struct FrameEvents;
+class String8;
+
+
enum class SupportableFrameTimestamps {
REQUESTED_PRESENT,
ACQUIRE,
@@ -32,8 +41,14 @@
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};
@@ -43,5 +58,72 @@
nsecs_t releaseTime{0};
};
+
+// A collection of timestamps corresponding to a single frame.
+struct FrameEvents {
+ void checkFencesForCompletion();
+ void dump(String8& outString) const;
+
+ bool valid{false};
+ 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 addRetireCalled{false};
+
+ nsecs_t postedTime{0};
+ nsecs_t requestedPresentTime{0};
+ nsecs_t latchTime{0};
+ nsecs_t firstRefreshStartTime{0};
+ nsecs_t lastRefreshStartTime{0};
+
+ nsecs_t acquireTime{0};
+ nsecs_t gpuCompositionDoneTime{0};
+ nsecs_t displayPresentTime{0};
+ nsecs_t displayRetireTime{0};
+ nsecs_t releaseTime{0};
+
+ sp<Fence> acquireFence{Fence::NO_FENCE};
+ sp<Fence> gpuCompositionDoneFence{Fence::NO_FENCE};
+ sp<Fence> displayPresentFence{Fence::NO_FENCE};
+ sp<Fence> displayRetireFence{Fence::NO_FENCE};
+ sp<Fence> releaseFence{Fence::NO_FENCE};
+};
+
+
+struct NewFrameEventsEntry {
+ uint64_t frameNumber{0};
+ nsecs_t postedTime{0};
+ nsecs_t requestedPresentTime{0};
+ sp<Fence> acquireFence{Fence::NO_FENCE};
+};
+
+
+class FrameEventHistory {
+public:
+ FrameEvents* getFrame(uint64_t frameNumber);
+ FrameEvents* getFrame(uint64_t frameNumber, size_t* iHint);
+ void checkFencesForCompletion();
+ void dump(String8& outString) const;
+
+ void addQueue(const NewFrameEventsEntry& newFrameEntry);
+ void addLatch(uint64_t frameNumber, nsecs_t latchTime);
+ void addPreComposition(uint64_t frameNumber, nsecs_t refreshStartTime);
+ void addPostComposition(uint64_t frameNumber,
+ sp<Fence> gpuCompositionDone, sp<Fence> displayPresent);
+ void addRetire(uint64_t frameNumber, sp<Fence> displayRetire);
+ void addRelease(uint64_t frameNumber, sp<Fence> release);
+
+private:
+ static constexpr size_t MAX_FRAME_HISTORY = 8;
+ std::array<FrameEvents, MAX_FRAME_HISTORY> mFrames;
+ size_t mQueueOffset{0};
+ size_t mCompositionOffset{0};
+ size_t mRetireOffset{0};
+ size_t mReleaseOffset{0};
+};
+
} // namespace android
#endif
diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h
index 0ab7590..8eab3c5 100644
--- a/include/gui/IConsumerListener.h
+++ b/include/gui/IConsumerListener.h
@@ -82,10 +82,13 @@
// different stream.
virtual void onSidebandStreamChanged() = 0; /* Asynchronous */
- // See IGraphicBufferProducer::getFrameTimestamps
- // This queries the consumer for the timestamps
- virtual bool getFrameTimestamps(uint64_t /*frameNumber*/,
- FrameTimestamps* /*outTimestamps*/) const { return false; }
+ // Notifies the consumer of any new producer-side events and then queries
+ // the consumer timestamps
+ virtual bool addAndGetFrameTimestamps(
+ const NewFrameEventsEntry* /*newTimestamps*/,
+ uint64_t /*frameNumber*/, FrameTimestamps* /*outTimestamps*/) {
+ return false;
+ }
};
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 20cffe0..493143a 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -594,7 +594,7 @@
//
// If a fence has not yet signaled the timestamp returned will be 0;
virtual bool getFrameTimestamps(uint64_t /*frameNumber*/,
- FrameTimestamps* /*outTimestamps*/) const { return false; }
+ FrameTimestamps* /*outTimestamps*/) { return false; }
// Returns a unique id for this BufferQueue
virtual status_t getUniqueId(uint64_t* outId) const = 0;
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 9ba85a6..bf758ce 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -71,6 +71,7 @@
"ConsumerBase.cpp",
"CpuConsumer.cpp",
"DisplayEventReceiver.cpp",
+ "FrameTimestamps.cpp",
"GLConsumer.cpp",
"GraphicBufferAlloc.cpp",
"GuiConfig.cpp",
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 47f5eba..6d4335e 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -61,13 +61,15 @@
}
}
-bool BufferQueue::ProxyConsumerListener::getFrameTimestamps(
- uint64_t frameNumber, FrameTimestamps* outTimestamps) const {
+bool BufferQueue::ProxyConsumerListener::addAndGetFrameTimestamps(
+ const NewFrameEventsEntry* newTimestamps,
+ uint64_t frameNumber, FrameTimestamps* outTimestamps) {
sp<ConsumerListener> listener(mConsumerListener.promote());
- if (listener != NULL) {
- return listener->getFrameTimestamps(frameNumber, outTimestamps);
+ if (listener == nullptr) {
+ return false;
}
- return false;
+ 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 81d4f31..6bd1cfd 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -740,19 +740,19 @@
ATRACE_CALL();
ATRACE_BUFFER_INDEX(slot);
- int64_t timestamp;
+ int64_t requestedPresentTimestamp;
bool isAutoTimestamp;
android_dataspace dataSpace;
Rect crop(Rect::EMPTY_RECT);
int scalingMode;
uint32_t transform;
uint32_t stickyTransform;
- sp<Fence> fence;
- input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode,
- &transform, &fence, &stickyTransform);
+ sp<Fence> acquireFence;
+ input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace,
+ &crop, &scalingMode, &transform, &acquireFence, &stickyTransform);
Region surfaceDamage = input.getSurfaceDamage();
- if (fence == NULL) {
+ if (acquireFence == NULL) {
BQ_LOGE("queueBuffer: fence is NULL");
return BAD_VALUE;
}
@@ -771,6 +771,7 @@
sp<IConsumerListener> frameAvailableListener;
sp<IConsumerListener> frameReplacedListener;
int callbackTicket = 0;
+ uint64_t currentFrameNumber = 0;
BufferItem item;
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
@@ -809,8 +810,9 @@
BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d"
" crop=[%d,%d,%d,%d] transform=%#x scale=%s",
- slot, mCore->mFrameCounter + 1, timestamp, dataSpace,
- crop.left, crop.top, crop.right, crop.bottom, transform,
+ slot, mCore->mFrameCounter + 1, requestedPresentTimestamp,
+ dataSpace, crop.left, crop.top, crop.right, crop.bottom,
+ transform,
BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode)));
const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
@@ -828,11 +830,14 @@
dataSpace = mCore->mDefaultBufferDataSpace;
}
- mSlots[slot].mFence = fence;
+ mSlots[slot].mFence = acquireFence;
mSlots[slot].mBufferState.queue();
+ // Increment the frame counter and store a local version of it
+ // for use outside the lock on mCore->mMutex.
++mCore->mFrameCounter;
- mSlots[slot].mFrameNumber = mCore->mFrameCounter;
+ currentFrameNumber = mCore->mFrameCounter;
+ mSlots[slot].mFrameNumber = currentFrameNumber;
item.mAcquireCalled = mSlots[slot].mAcquireCalled;
item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
@@ -842,12 +847,12 @@
item.mTransformToDisplayInverse =
(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
item.mScalingMode = static_cast<uint32_t>(scalingMode);
- item.mTimestamp = timestamp;
+ item.mTimestamp = requestedPresentTimestamp;
item.mIsAutoTimestamp = isAutoTimestamp;
item.mDataSpace = dataSpace;
- item.mFrameNumber = mCore->mFrameCounter;
+ item.mFrameNumber = currentFrameNumber;
item.mSlot = slot;
- item.mFence = fence;
+ item.mFence = acquireFence;
item.mIsDroppable = mCore->mAsyncMode ||
mCore->mDequeueBufferCannotBlock ||
(mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot);
@@ -958,10 +963,20 @@
// small trade-off in favor of latency rather than throughput.
mLastQueueBufferFence->waitForever("Throttling EGL Production");
}
- mLastQueueBufferFence = fence;
+ mLastQueueBufferFence = acquireFence;
mLastQueuedCrop = item.mCrop;
mLastQueuedTransform = item.mTransform;
+ // Update and get FrameEventHistory.
+ nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ NewFrameEventsEntry newFrameEventsEntry = {
+ currentFrameNumber,
+ postedTime,
+ requestedPresentTimestamp,
+ acquireFence
+ };
+ addAndGetFrameTimestamps(&newFrameEventsEntry, 0, nullptr);
+
return NO_ERROR;
}
@@ -1449,18 +1464,28 @@
return NO_ERROR;
}
-bool BufferQueueProducer::getFrameTimestamps(uint64_t frameNumber,
- FrameTimestamps* outTimestamps) const {
- ATRACE_CALL();
- BQ_LOGV("getFrameTimestamps, %" PRIu64, frameNumber);
- sp<IConsumerListener> listener;
+bool BufferQueueProducer::getFrameTimestamps(
+ uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+ return addAndGetFrameTimestamps(nullptr, frameNumber, outTimestamps);
+}
+bool BufferQueueProducer::addAndGetFrameTimestamps(
+ const NewFrameEventsEntry* newTimestamps,
+ uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+ if (newTimestamps == nullptr && outTimestamps == nullptr) {
+ return false;
+ }
+
+ ATRACE_CALL();
+ BQ_LOGV("addAndGetFrameTimestamps");
+ sp<IConsumerListener> listener;
{
Mutex::Autolock lock(mCore->mMutex);
listener = mCore->mConsumerListener;
}
if (listener != NULL) {
- return listener->getFrameTimestamps(frameNumber, outTimestamps);
+ return listener->addAndGetFrameTimestamps(
+ newTimestamps, frameNumber, outTimestamps);
}
return false;
}
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
new file mode 100644
index 0000000..a919911
--- /dev/null
+++ b/libs/gui/FrameTimestamps.cpp
@@ -0,0 +1,290 @@
+/*
+* 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.
+*/
+
+#include <gui/FrameTimestamps.h>
+
+#include <inttypes.h>
+#include <utils/String8.h>
+
+#include <algorithm>
+#include <limits>
+
+namespace android {
+
+static inline bool isValidTimestamp(nsecs_t time) {
+ return time > 0 && time < INT64_MAX;
+}
+
+// ============================================================================
+// 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
+// ============================================================================
+
+static void checkFenceForCompletion(sp<Fence>* fence, nsecs_t* dstTime) {
+ if ((*fence)->isValid()) {
+ nsecs_t time = (*fence)->getSignalTime();
+ if (isValidTimestamp(time)) {
+ *dstTime = time;
+ *fence = Fence::NO_FENCE;
+ }
+ }
+}
+
+void FrameEvents::checkFencesForCompletion() {
+ checkFenceForCompletion(&acquireFence, &acquireTime);
+ checkFenceForCompletion(&gpuCompositionDoneFence, &gpuCompositionDoneTime);
+ checkFenceForCompletion(&displayPresentFence, &displayPresentTime);
+ checkFenceForCompletion(&displayRetireFence, &displayRetireTime);
+ checkFenceForCompletion(&releaseFence, &releaseTime);
+}
+
+void FrameEvents::dump(String8& outString) const
+{
+ if (!valid) {
+ return;
+ }
+
+ outString.appendFormat("-- Frame %" PRIu64 "\n", frameNumber);
+ outString.appendFormat("--- Posted \t%" PRId64 "\n", postedTime);
+ outString.appendFormat("--- Req. Present\t%" PRId64 "\n", requestedPresentTime);
+
+ outString.appendFormat("--- Latched \t");
+ if (isValidTimestamp(latchTime)) {
+ outString.appendFormat("%" PRId64 "\n", latchTime);
+ } else {
+ outString.appendFormat("Pending\n");
+ }
+
+ outString.appendFormat("--- Refresh (First)\t");
+ if (isValidTimestamp(firstRefreshStartTime)) {
+ outString.appendFormat("%" PRId64 "\n", firstRefreshStartTime);
+ } else {
+ outString.appendFormat("Pending\n");
+ }
+
+ outString.appendFormat("--- Refresh (Last)\t");
+ if (isValidTimestamp(lastRefreshStartTime)) {
+ outString.appendFormat("%" PRId64 "\n", lastRefreshStartTime);
+ } else {
+ outString.appendFormat("Pending\n");
+ }
+
+ outString.appendFormat("--- Acquire \t");
+ if (isValidTimestamp(acquireTime)) {
+ outString.appendFormat("%" PRId64 "\n", acquireTime);
+ } else {
+ outString.appendFormat("Pending\n");
+ }
+
+ outString.appendFormat("--- GPU Composite Done\t");
+ if (isValidTimestamp(gpuCompositionDoneTime)) {
+ outString.appendFormat("%" PRId64 "\n", gpuCompositionDoneTime);
+ } else if (!addPostCompositeCalled || gpuCompositionDoneFence->isValid()) {
+ outString.appendFormat("Pending\n");
+ } else {
+ outString.appendFormat("N/A\n");
+ }
+
+ outString.appendFormat("--- Display Present\t");
+ if (isValidTimestamp(displayPresentTime)) {
+ outString.appendFormat("%" PRId64 "\n", displayPresentTime);
+ } else if (!addPostCompositeCalled || displayPresentFence->isValid()) {
+ outString.appendFormat("Pending\n");
+ } else {
+ outString.appendFormat("N/A\n");
+ }
+
+ outString.appendFormat("--- Display Retire\t");
+ if (isValidTimestamp(displayRetireTime)) {
+ outString.appendFormat("%" PRId64 "\n", displayRetireTime);
+ } else if (!addRetireCalled || displayRetireFence->isValid()) {
+ outString.appendFormat("Pending\n");
+ } else {
+ outString.appendFormat("N/A\n");
+ }
+
+ outString.appendFormat("--- Release \t");
+ if (isValidTimestamp(releaseTime)) {
+ outString.appendFormat("%" PRId64 "\n", releaseTime);
+ } else {
+ outString.appendFormat("Pending\n");
+ }
+}
+
+
+// ============================================================================
+// FrameEventHistory
+// ============================================================================
+
+namespace {
+
+struct FrameNumberEqual {
+ FrameNumberEqual(uint64_t frameNumber) : mFrameNumber(frameNumber) {}
+ bool operator()(const FrameEvents& frame) {
+ return frame.valid && mFrameNumber == frame.frameNumber;
+ }
+ const uint64_t mFrameNumber;
+};
+
+} // namespace
+
+
+FrameEvents* FrameEventHistory::getFrame(uint64_t frameNumber) {
+ auto frame = std::find_if(
+ mFrames.begin(), mFrames.end(), FrameNumberEqual(frameNumber));
+ return frame == mFrames.end() ? nullptr : &(*frame);
+}
+
+FrameEvents* FrameEventHistory::getFrame(uint64_t frameNumber, size_t* iHint) {
+ *iHint = std::min(*iHint, mFrames.size());
+ auto hint = mFrames.begin() + *iHint;
+ auto frame = std::find_if(
+ hint, mFrames.end(), FrameNumberEqual(frameNumber));
+ if (frame == mFrames.end()) {
+ frame = std::find_if(
+ mFrames.begin(), hint, FrameNumberEqual(frameNumber));
+ if (frame == hint) {
+ return nullptr;
+ }
+ }
+ *iHint = static_cast<size_t>(std::distance(mFrames.begin(), frame));
+ return &(*frame);
+}
+
+void FrameEventHistory::checkFencesForCompletion() {
+ for (auto& frame : mFrames) {
+ frame.checkFencesForCompletion();
+ }
+}
+
+// Uses !|valid| as the MSB.
+static bool FrameNumberLessThan(
+ const FrameEvents& lhs, const FrameEvents& rhs) {
+ if (lhs.valid == rhs.valid) {
+ return lhs.frameNumber < rhs.frameNumber;
+ }
+ return lhs.valid;
+}
+
+void FrameEventHistory::dump(String8& outString) const {
+ auto earliestFrame = std::min_element(
+ mFrames.begin(), mFrames.end(), &FrameNumberLessThan);
+ if (!earliestFrame->valid) {
+ outString.appendFormat("-- N/A\n");
+ return;
+ }
+ for (auto frame = earliestFrame; frame != mFrames.end(); ++frame) {
+ frame->dump(outString);
+ }
+ for (auto frame = mFrames.begin(); frame != earliestFrame; ++frame) {
+ frame->dump(outString);
+ }
+}
+
+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;
+ }
+}
+
+void FrameEventHistory::addLatch(uint64_t frameNumber, nsecs_t latchTime) {
+ FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset);
+ 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.");
+ 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;
+ }
+ }
+}
+
+void FrameEventHistory::addRetire(
+ uint64_t frameNumber, sp<Fence> displayRetire) {
+ FrameEvents* frame = getFrame(frameNumber, &mRetireOffset);
+ if (frame == nullptr) {
+ ALOGE("FrameEventHistory::addRetire: Did not find frame.");
+ return;
+ }
+ frame->addRetireCalled = true;
+ frame->displayRetireFence = displayRetire;
+}
+
+void FrameEventHistory::addRelease(
+ uint64_t frameNumber, sp<Fence> release) {
+ FrameEvents* frame = getFrame(frameNumber, &mReleaseOffset);
+ if (frame == nullptr) {
+ ALOGE("FrameEventHistory::addRelease: Did not find frame.");
+ return;
+ }
+ frame->releaseFence = release;
+}
+
+} // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 89f852c..a4de7eb 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -430,7 +430,7 @@
}
virtual bool getFrameTimestamps(uint64_t frameNumber,
- FrameTimestamps* outTimestamps) const {
+ FrameTimestamps* outTimestamps) {
Parcel data, reply;
status_t result = data.writeInterfaceToken(
IGraphicBufferProducer::getInterfaceDescriptor());
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 7135ed3..dd8719a 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -10,7 +10,6 @@
DispSync.cpp \
EventControlThread.cpp \
EventThread.cpp \
- FenceTracker.cpp \
FrameTracker.cpp \
GpuService.cpp \
Layer.cpp \
diff --git a/services/surfaceflinger/FenceTracker.cpp b/services/surfaceflinger/FenceTracker.cpp
deleted file mode 100644
index 4dac0db..0000000
--- a/services/surfaceflinger/FenceTracker.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * 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.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include <inttypes.h>
-#include "FenceTracker.h"
-#include "Layer.h"
-#include <utils/Trace.h>
-
-namespace android {
-
-FenceTracker::FenceTracker() :
- mFrameCounter(0),
- mOffset(0),
- mFrames(),
- mMutex() {
-}
-
-void FenceTracker::dump(String8* outString) {
- Mutex::Autolock lock(mMutex);
- checkFencesForCompletion();
-
- for (size_t i = 0; i < MAX_FRAME_HISTORY; i++) {
- int index = (mOffset + i) % MAX_FRAME_HISTORY;
- const FrameRecord& frame = mFrames[index];
-
- outString->appendFormat("Frame %" PRIu64 "\n", frame.frameId);
- outString->appendFormat("- Refresh start\t%" PRId64 "\n",
- frame.refreshStartTime);
-
- if (frame.glesCompositionDoneTime) {
- outString->appendFormat("- GLES done\t%" PRId64 "\n",
- frame.glesCompositionDoneTime);
- } else if (frame.glesCompositionDoneFence != Fence::NO_FENCE) {
- outString->append("- GLES done\tNot signaled\n");
- }
-
- if (frame.presentTime) {
- outString->appendFormat("- Present\t%" PRId64 "\n",
- frame.presentTime);
- } else if (frame.presentFence != Fence::NO_FENCE) {
- outString->append("- Present\tNot signaled\n");
- }
-
- if (frame.retireTime) {
- outString->appendFormat("- Retire\t%" PRId64 "\n",
- frame.retireTime);
- } else if (frame.retireFence != Fence::NO_FENCE) {
- outString->append("- Retire\tNot signaled\n");
- }
-
- for (const auto& kv : frame.layers) {
- const LayerRecord& layer = kv.second;
- outString->appendFormat("-- %s\n", layer.name.string());
- outString->appendFormat("---- Frame # %" PRIu64 " (%s)\n",
- layer.frameNumber,
- layer.isGlesComposition ? "GLES" : "HWC");
- outString->appendFormat("---- Req.Present.\t%" PRId64 "\n",
- layer.requestedPresentTime);
- if (layer.acquireTime) {
- outString->appendFormat("---- Acquire\t%" PRId64 "\n",
- layer.acquireTime);
- } else {
- outString->append("---- Acquire\tNot signaled\n");
- }
- if (layer.releaseTime) {
- outString->appendFormat("---- Release\t%" PRId64 "\n",
- layer.releaseTime);
- } else {
- outString->append("---- Release\tNot signaled\n");
- }
- }
- }
-}
-
-static inline bool isValidTimestamp(nsecs_t time) {
- return time > 0 && time < INT64_MAX;
-}
-
-void FenceTracker::checkFencesForCompletion() {
- ATRACE_CALL();
- for (auto& frame : mFrames) {
- if (frame.presentFence != Fence::NO_FENCE) {
- nsecs_t time = frame.presentFence->getSignalTime();
- if (isValidTimestamp(time)) {
- frame.presentTime = time;
- frame.presentFence = Fence::NO_FENCE;
- }
- }
- if (frame.retireFence != Fence::NO_FENCE) {
- nsecs_t time = frame.retireFence->getSignalTime();
- if (isValidTimestamp(time)) {
- frame.retireTime = time;
- frame.retireFence = Fence::NO_FENCE;
- }
- }
- if (frame.glesCompositionDoneFence != Fence::NO_FENCE) {
- nsecs_t time = frame.glesCompositionDoneFence->getSignalTime();
- if (isValidTimestamp(time)) {
- frame.glesCompositionDoneTime = time;
- frame.glesCompositionDoneFence = Fence::NO_FENCE;
- }
- }
- for (auto& kv : frame.layers) {
- LayerRecord& layer = kv.second;
- if (layer.acquireFence != Fence::NO_FENCE) {
- nsecs_t time = layer.acquireFence->getSignalTime();
- if (isValidTimestamp(time)) {
- layer.acquireTime = time;
- layer.acquireFence = Fence::NO_FENCE;
- }
- }
- if (layer.releaseFence != Fence::NO_FENCE) {
- nsecs_t time = layer.releaseFence->getSignalTime();
- if (isValidTimestamp(time)) {
- layer.releaseTime = time;
- layer.releaseFence = Fence::NO_FENCE;
- }
- }
- }
- }
-}
-
-void FenceTracker::addFrame(nsecs_t refreshStartTime, sp<Fence> presentFence,
- sp<Fence> retireFence, const Vector<sp<Layer>>& layers,
- sp<Fence> glDoneFence) {
- ATRACE_CALL();
- Mutex::Autolock lock(mMutex);
- FrameRecord& frame = mFrames[mOffset];
- FrameRecord& prevFrame = mFrames[(mOffset + MAX_FRAME_HISTORY - 1) %
- MAX_FRAME_HISTORY];
- frame.layers.clear();
-
- bool wasGlesCompositionDone = false;
- const size_t count = layers.size();
- for (size_t i = 0; i < count; i++) {
- String8 name;
- uint64_t frameNumber;
- bool glesComposition;
- nsecs_t requestedPresentTime;
- sp<Fence> acquireFence;
- sp<Fence> prevReleaseFence;
- int32_t layerId = layers[i]->getSequence();
-
- layers[i]->getFenceData(&name, &frameNumber, &glesComposition,
- &requestedPresentTime, &acquireFence, &prevReleaseFence);
-
- frame.layers.emplace(std::piecewise_construct,
- std::forward_as_tuple(layerId),
- std::forward_as_tuple(name, frameNumber, glesComposition,
- requestedPresentTime, 0, 0, acquireFence, Fence::NO_FENCE));
- auto prevLayer = prevFrame.layers.find(layerId);
- if (prevLayer != prevFrame.layers.end()) {
- if (frameNumber != prevLayer->second.frameNumber) {
- prevLayer->second.releaseFence = prevReleaseFence;
- }
- }
- }
-
- frame.frameId = mFrameCounter;
- frame.refreshStartTime = refreshStartTime;
- frame.presentTime = 0;
- frame.retireTime = 0;
- frame.glesCompositionDoneTime = 0;
- frame.presentFence = presentFence;
- prevFrame.retireFence = retireFence;
- frame.retireFence = Fence::NO_FENCE;
- frame.glesCompositionDoneFence = wasGlesCompositionDone ? glDoneFence :
- Fence::NO_FENCE;
-
- mOffset = (mOffset + 1) % MAX_FRAME_HISTORY;
- mFrameCounter++;
-}
-
-bool FenceTracker::getFrameTimestamps(const Layer& layer,
- uint64_t frameNumber, FrameTimestamps* outTimestamps) {
- Mutex::Autolock lock(mMutex);
- checkFencesForCompletion();
- int32_t layerId = layer.getSequence();
-
- size_t i = 0;
- for (; i < MAX_FRAME_HISTORY; i++) {
- if (mFrames[i].layers.count(layerId) &&
- mFrames[i].layers[layerId].frameNumber == frameNumber) {
- break;
- }
- }
- if (i == MAX_FRAME_HISTORY) {
- return false;
- }
-
- const FrameRecord& frameRecord = mFrames[i];
- const LayerRecord& layerRecord = mFrames[i].layers[layerId];
- outTimestamps->frameNumber = frameNumber;
- outTimestamps->requestedPresentTime = layerRecord.requestedPresentTime;
- outTimestamps->acquireTime = layerRecord.acquireTime;
- outTimestamps->refreshStartTime = frameRecord.refreshStartTime;
- outTimestamps->glCompositionDoneTime = frameRecord.glesCompositionDoneTime;
- outTimestamps->displayPresentTime = frameRecord.presentTime;
- outTimestamps->displayRetireTime = frameRecord.retireTime;
- outTimestamps->releaseTime = layerRecord.releaseTime;
- return true;
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/FenceTracker.h b/services/surfaceflinger/FenceTracker.h
deleted file mode 100644
index 3b429d1..0000000
--- a/services/surfaceflinger/FenceTracker.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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_FENCETRACKER_H
-#define ANDROID_FENCETRACKER_H
-
-#include <ui/Fence.h>
-#include <utils/Mutex.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
-#include <unordered_map>
-
-namespace android {
-
-class Layer;
-struct FrameTimestamps;
-/*
- * Keeps a circular buffer of fence/timestamp data for the last N frames in
- * SurfaceFlinger. Gets timestamps for fences after they have signaled.
- */
-class FenceTracker {
-public:
- FenceTracker();
- void dump(String8* outString);
- void addFrame(nsecs_t refreshStartTime, sp<Fence> presentFence,
- sp<Fence> retireFence, const Vector<sp<Layer>>& layers,
- sp<Fence> glDoneFence);
- bool getFrameTimestamps(const Layer& layer, uint64_t frameNumber,
- FrameTimestamps* outTimestamps);
-
-protected:
- static constexpr size_t MAX_FRAME_HISTORY = 8;
-
- struct LayerRecord {
- String8 name; // layer name
- uint64_t frameNumber; // frame number for this layer
- bool isGlesComposition; // was GLES composition used for this layer?
- // time the producer requested this frame be presented
- nsecs_t requestedPresentTime;
- nsecs_t acquireTime; // timestamp from the acquire fence
- nsecs_t releaseTime; // timestamp from the release fence
- sp<Fence> acquireFence; // acquire fence
- sp<Fence> releaseFence; // release fence
-
- LayerRecord(const String8& name, uint64_t frameNumber,
- bool isGlesComposition, nsecs_t requestedPresentTime,
- nsecs_t acquireTime, nsecs_t releaseTime,
- sp<Fence> acquireFence, sp<Fence> releaseFence) :
- name(name), frameNumber(frameNumber),
- isGlesComposition(isGlesComposition),
- requestedPresentTime(requestedPresentTime),
- acquireTime(acquireTime), releaseTime(releaseTime),
- acquireFence(acquireFence), releaseFence(releaseFence) {};
- LayerRecord() : name("uninitialized"), frameNumber(0),
- isGlesComposition(false), requestedPresentTime(0),
- acquireTime(0), releaseTime(0), acquireFence(Fence::NO_FENCE),
- releaseFence(Fence::NO_FENCE) {};
- };
-
- struct FrameRecord {
- // global SurfaceFlinger frame counter
- uint64_t frameId;
- // layer data for this frame
- std::unordered_map<int32_t, LayerRecord> layers;
- // timestamp for when SurfaceFlinger::handleMessageRefresh() was called
- nsecs_t refreshStartTime;
- // timestamp from the present fence
- nsecs_t presentTime;
- // timestamp from the retire fence
- nsecs_t retireTime;
- // timestamp from the GLES composition completion fence
- nsecs_t glesCompositionDoneTime;
- // primary display present fence for this frame
- sp<Fence> presentFence;
- // primary display retire fence for this frame
- sp<Fence> retireFence;
- // if GLES composition was done, the fence for its completion
- sp<Fence> glesCompositionDoneFence;
-
- FrameRecord() : frameId(0), layers(), refreshStartTime(0),
- presentTime(0), retireTime(0), glesCompositionDoneTime(0),
- presentFence(Fence::NO_FENCE), retireFence(Fence::NO_FENCE),
- glesCompositionDoneFence(Fence::NO_FENCE) {}
- };
-
- uint64_t mFrameCounter;
- uint32_t mOffset;
- FrameRecord mFrames[MAX_FRAME_HISTORY];
- Mutex mMutex;
-
- void checkFencesForCompletion();
-};
-
-}
-
-#endif // ANDROID_FRAMETRACKER_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 4772fc1..c16af59 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -80,7 +80,9 @@
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mOverrideScalingMode(-1),
mCurrentOpacity(true),
+ mBufferLatched(false),
mCurrentFrameNumber(0),
+ mPreviousFrameNumber(-1U),
mRefreshPending(false),
mFrameLatencyNeeded(false),
mFiltering(false),
@@ -1729,14 +1731,53 @@
return isDue || !isPlausible;
}
-bool Layer::onPreComposition() {
+bool Layer::onPreComposition(nsecs_t refreshStartTime) {
+ if (mBufferLatched) {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
+ }
mRefreshPending = false;
return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
}
-bool Layer::onPostComposition() {
+bool Layer::onPostComposition(sp<Fence> glDoneFence) {
+ // mFrameLatencyNeeded is true when a new frame was latched for the
+ // composition.
bool frameLatencyNeeded = mFrameLatencyNeeded;
if (mFrameLatencyNeeded) {
+ const HWComposer& hwc = mFlinger->getHwComposer();
+#ifdef USE_HWC2
+ sp<Fence> retireFence = Fence::NO_FENCE;
+ sp<Fence> presentFence = Fence::NO_FENCE;
+ sp<Fence> presentOrRetireFence = Fence::NO_FENCE;
+ if (hwc.retireFenceRepresentsStartOfScanout()) {
+ presentFence = hwc.getRetireFence(HWC_DISPLAY_PRIMARY);
+ presentOrRetireFence = presentFence;
+ } else {
+ retireFence = hwc.getRetireFence(HWC_DISPLAY_PRIMARY);
+ presentOrRetireFence = retireFence;
+ }
+ bool wasGpuComposited = mHwcLayers.count(HWC_DISPLAY_PRIMARY) ?
+ mHwcLayers.at(HWC_DISPLAY_PRIMARY).compositionType ==
+ HWC2::Composition::Client : true;
+#else
+ sp<Fence> retireFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
+ sp<Fence> presentFence = Fence::NO_FENCE;
+ sp<Fence> presentOrRetireFence = retireFence;
+ bool wasGpuComposited = mIsGlesComposition;
+#endif
+
+ // Update mFrameEventHistory.
+ {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.addPostComposition(mCurrentFrameNumber,
+ wasGpuComposited ? glDoneFence : Fence::NO_FENCE,
+ presentFence);
+ mFrameEventHistory.addRetire(mPreviousFrameNumber,
+ retireFence);
+ }
+
+ // Update mFrameTracker.
nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp();
mFrameTracker.setDesiredPresentTime(desiredPresentTime);
@@ -1749,14 +1790,8 @@
mFrameTracker.setFrameReadyTime(desiredPresentTime);
}
- const HWComposer& hwc = mFlinger->getHwComposer();
-#ifdef USE_HWC2
- sp<Fence> presentFence = hwc.getRetireFence(HWC_DISPLAY_PRIMARY);
-#else
- sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
-#endif
- if (presentFence->isValid()) {
- mFrameTracker.setActualPresentFence(presentFence);
+ if (presentOrRetireFence->isValid()) {
+ mFrameTracker.setActualPresentFence(presentOrRetireFence);
} else {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
@@ -1773,6 +1808,9 @@
#ifdef USE_HWC2
void Layer::releasePendingBuffer() {
mSurfaceFlingerConsumer->releasePendingBuffer();
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.addRelease(mPreviousFrameNumber,
+ mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
}
#endif
@@ -1813,7 +1851,7 @@
return !matchingFramesFound || allTransactionsApplied;
}
-Region Layer::latchBuffer(bool& recomputeVisibleRegions)
+Region Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime)
{
ATRACE_CALL();
@@ -1937,6 +1975,19 @@
return outDirtyRegion;
}
+ mBufferLatched = true;
+ mPreviousFrameNumber = mCurrentFrameNumber;
+ mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
+ {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
+#ifndef USE_HWC2
+ mFrameEventHistory.addRelease(mPreviousFrameNumber,
+ mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
+#endif
+ }
+
mRefreshPending = true;
mFrameLatencyNeeded = true;
if (oldActiveBuffer == NULL) {
@@ -1972,8 +2023,6 @@
recomputeVisibleRegions = true;
}
- mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
-
// Remove any sync points corresponding to the buffer which was just
// latched
{
@@ -2158,22 +2207,32 @@
mFrameTracker.getStats(outStats);
}
-void Layer::getFenceData(String8* outName, uint64_t* outFrameNumber,
- bool* outIsGlesComposition, nsecs_t* outRequestedPresentTime,
- sp<Fence>* outAcquireFence, sp<Fence>* outPrevReleaseFence) const {
- *outName = mName;
- *outFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+void Layer::dumpFrameEvents(String8& result) {
+ result.appendFormat("- Layer %s (%s, %p)\n",
+ getName().string(), getTypeId(), this);
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.checkFencesForCompletion();
+ mFrameEventHistory.dump(result);
+}
-#ifdef USE_HWC2
- *outIsGlesComposition = mHwcLayers.count(HWC_DISPLAY_PRIMARY) ?
- mHwcLayers.at(HWC_DISPLAY_PRIMARY).compositionType ==
- HWC2::Composition::Client : true;
-#else
- *outIsGlesComposition = mIsGlesComposition;
-#endif
- *outRequestedPresentTime = mSurfaceFlingerConsumer->getTimestamp();
- *outAcquireFence = mSurfaceFlingerConsumer->getCurrentFence();
- *outPrevReleaseFence = mSurfaceFlingerConsumer->getPrevFinalReleaseFence();
+bool Layer::addAndGetFrameTimestamps(
+ const NewFrameEventsEntry* newTimestamps,
+ uint64_t frameNumber, FrameTimestamps *outTimestamps) {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ if (newTimestamps) {
+ mFrameEventHistory.addQueue(*newTimestamps);
+ }
+
+ if (outTimestamps) {
+ FrameEvents* frameEvents = mFrameEventHistory.getFrame(frameNumber);
+ if (frameEvents) {
+ frameEvents->checkFencesForCompletion();
+ *outTimestamps = FrameTimestamps(*frameEvents);
+ return true;
+ }
+ }
+
+ return false;
}
std::vector<OccupancyTracker::Segment> Layer::getOccupancyHistory(
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 5aba69b..98ea053 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -270,13 +270,13 @@
* called before composition.
* returns true if the layer has pending updates.
*/
- bool onPreComposition();
+ bool onPreComposition(nsecs_t refreshStartTime);
/*
* called after composition.
* returns true if the layer latched a new buffer this frame.
*/
- bool onPostComposition();
+ bool onPostComposition(sp<Fence> glCompositionDoneFence);
#ifdef USE_HWC2
// If a buffer was replaced this frame, release the former buffer
@@ -323,7 +323,7 @@
* operation, so this should be set only if needed). Typically this is used
* to figure out if the content or size of a surface has changed.
*/
- Region latchBuffer(bool& recomputeVisibleRegions);
+ Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime);
bool isPotentialCursor() const { return mPotentialCursor;}
@@ -402,20 +402,17 @@
void miniDump(String8& result, int32_t hwcId) const;
#endif
void dumpFrameStats(String8& result) const;
+ void dumpFrameEvents(String8& result);
void clearFrameStats();
void logFrameStats();
void getFrameStats(FrameStats* outStats) const;
- void getFenceData(String8* outName, uint64_t* outFrameNumber,
- bool* outIsGlesComposition, nsecs_t* outRequestedPresentTime,
- sp<Fence>* outAcquireFence, sp<Fence>* outPrevReleaseFence) const;
std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush);
- bool getFrameTimestamps(uint64_t frameNumber,
- FrameTimestamps* outTimestamps) const {
- return mFlinger->getFrameTimestamps(*this, frameNumber, outTimestamps);
- }
+ bool addAndGetFrameTimestamps(
+ const NewFrameEventsEntry* newTimestamps,
+ uint64_t frameNumber, FrameTimestamps* outTimestamps);
bool getTransformToDisplayInverse() const;
@@ -583,8 +580,15 @@
// thread-safe
volatile int32_t mQueuedFrames;
volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
+
+ // Timestamp history for UIAutomation. Thread safe.
FrameTracker mFrameTracker;
+ // Timestamp history for the consumer to query.
+ // Accessed by both consumer and producer on main and binder threads.
+ Mutex mFrameEventHistoryMutex;
+ FrameEventHistory mFrameEventHistory;
+
// main thread
sp<GraphicBuffer> mActiveBuffer;
sp<NativeHandle> mSidebandStream;
@@ -594,7 +598,9 @@
// We encode unset as -1.
int32_t mOverrideScalingMode;
bool mCurrentOpacity;
+ bool mBufferLatched = false; // TODO: Use mActiveBuffer?
std::atomic<uint64_t> mCurrentFrameNumber;
+ uint64_t mPreviousFrameNumber; // Only accessed on the main thread.
bool mRefreshPending;
bool mFrameLatencyNeeded;
// Whether filtering is forced on or not
@@ -644,7 +650,7 @@
Condition mQueueItemCondition;
Vector<BufferItem> mQueueItems;
std::atomic<uint64_t> mLastFrameNumberReceived;
- bool mUpdateTexImageFailed; // This is only modified from the main thread
+ bool mUpdateTexImageFailed; // This is only accessed on the main thread.
bool mAutoRefresh;
bool mFreezePositionUpdates;
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index ffaee7a..4604e01 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -145,6 +145,11 @@
outTransformMatrix);
}
+bool MonitoredProducer::getFrameTimestamps(
+ uint64_t frameNumber, FrameTimestamps* outTimestamps) {
+ return mProducer->getFrameTimestamps(frameNumber, outTimestamps);
+}
+
status_t MonitoredProducer::getUniqueId(uint64_t* outId) const {
return mProducer->getUniqueId(outId);
}
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index 66f6cf0..5a2351f 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -63,6 +63,8 @@
virtual IBinder* onAsBinder();
virtual status_t setSharedBufferMode(bool sharedBufferMode) override;
virtual status_t setAutoRefresh(bool autoRefresh) override;
+ virtual bool getFrameTimestamps(uint64_t frameNumber,
+ FrameTimestamps* outTimestamps) override;
virtual status_t getUniqueId(uint64_t* outId) const override;
private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2f273ae..8400136 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1132,12 +1132,12 @@
nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
- preComposition();
+ preComposition(refreshStartTime);
rebuildLayerStacks();
setUpHWComposer();
doDebugFlashRegions();
doComposition();
- postComposition(refreshStartTime);
+ postComposition();
mPreviousPresentFence = mHwc->getRetireFence(HWC_DISPLAY_PRIMARY);
@@ -1195,7 +1195,7 @@
}
}
-void SurfaceFlinger::preComposition()
+void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
{
ATRACE_CALL();
ALOGV("preComposition");
@@ -1204,7 +1204,7 @@
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
- if (layers[i]->onPreComposition()) {
+ if (layers[i]->onPreComposition(refreshStartTime)) {
needExtraInvalidate = true;
}
}
@@ -1213,7 +1213,7 @@
}
}
-void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
+void SurfaceFlinger::postComposition()
{
ATRACE_CALL();
ALOGV("postComposition");
@@ -1223,10 +1223,16 @@
layer->releasePendingBuffer();
}
+ bool hadClientComposition = mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY);
+
+ const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+ sp<Fence> glCompositionDoneFence = hadClientComposition
+ ? hw->getClientTargetAcquireFence()
+ : Fence::NO_FENCE;
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
- bool frameLatched = layers[i]->onPostComposition();
+ bool frameLatched = layers[i]->onPostComposition(glCompositionDoneFence);
if (frameLatched) {
recordBufferingStats(layers[i]->getName().string(),
layers[i]->getOccupancyHistory(false));
@@ -1243,26 +1249,12 @@
}
}
- const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
if (kIgnorePresentFences) {
if (hw->isDisplayOn()) {
enableHardwareVsync();
}
}
- sp<Fence> fenceTrackerPresentFence;
- sp<Fence> fenceTrackerRetireFence;
- if (mHwc->retireFenceRepresentsStartOfScanout()) {
- fenceTrackerPresentFence = presentFence;
- fenceTrackerRetireFence = Fence::NO_FENCE;
- } else {
- fenceTrackerPresentFence = Fence::NO_FENCE;
- fenceTrackerRetireFence = presentFence;
- }
- mFenceTracker.addFrame(refreshStartTime,
- fenceTrackerPresentFence, fenceTrackerRetireFence,
- hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
-
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
@@ -2019,6 +2011,7 @@
{
ALOGV("handlePageFlip");
+ nsecs_t latchTime = systemTime();
Region dirtyRegion;
bool visibleRegions = false;
@@ -2048,7 +2041,7 @@
}
}
for (auto& layer : mLayersWithQueuedFrames) {
- const Region dirty(layer->latchBuffer(visibleRegions));
+ const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
layer->useSurfaceDamage();
const Layer::State& s(layer->getDrawingState());
invalidateLayerStack(s.layerStack, dirty);
@@ -2845,9 +2838,9 @@
}
if ((index < numArgs) &&
- (args[index] == String16("--fences"))) {
+ (args[index] == String16("--frame-events"))) {
index++;
- mFenceTracker.dump(&result);
+ dumpFrameEventsLocked(result);
dumpAll = false;
}
}
@@ -2988,6 +2981,16 @@
}
}
+void SurfaceFlinger::dumpFrameEventsLocked(String8& result) {
+ result.appendFormat("Layer frame timestamps:\n");
+
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ currentLayers[i]->dumpFrameEvents(result);
+ }
+}
+
void SurfaceFlinger::dumpBufferingStats(String8& result) const {
result.append("Buffering stats:\n");
result.append(" [Layer name] <Active time> <Two buffer> "
@@ -3907,11 +3910,6 @@
}
}
-bool SurfaceFlinger::getFrameTimestamps(const Layer& layer,
- uint64_t frameNumber, FrameTimestamps* outTimestamps) {
- return mFenceTracker.getFrameTimestamps(layer, frameNumber, outTimestamps);
-}
-
// ---------------------------------------------------------------------------
SurfaceFlinger::LayerVector::LayerVector() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index bdb2614..5b216dd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -53,7 +53,6 @@
#include "Barrier.h"
#include "DisplayDevice.h"
#include "DispSync.h"
-#include "FenceTracker.h"
#include "FrameTracker.h"
#include "MessageQueue.h"
#include "SurfaceInterceptor.h"
@@ -401,8 +400,8 @@
const LayerVector& currentLayers, uint32_t layerStack,
Region& dirtyRegion, Region& opaqueRegion);
- void preComposition();
- void postComposition(nsecs_t refreshStartTime);
+ void preComposition(nsecs_t refreshStartTime);
+ void postComposition();
void rebuildLayerStacks();
void setUpHWComposer();
void doComposition();
@@ -446,14 +445,13 @@
void logFrameStats();
void dumpStaticScreenStats(String8& result) const;
+ // Not const because each Layer needs to query Fences and cache timestamps.
+ void dumpFrameEventsLocked(String8& result);
void recordBufferingStats(const char* layerName,
std::vector<OccupancyTracker::Segment>&& history);
void dumpBufferingStats(String8& result) const;
- bool getFrameTimestamps(const Layer& layer, uint64_t frameNumber,
- FrameTimestamps* outTimestamps);
-
/* ------------------------------------------------------------------------
* Attributes
*/
@@ -519,7 +517,6 @@
nsecs_t mLastTransactionTime;
bool mBootFinished;
bool mForceFullDamage;
- FenceTracker mFenceTracker;
#ifdef USE_HWC2
bool mPropagateBackpressure = true;
#endif
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 5317cc7..1ef7065 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -248,10 +248,15 @@
}
}
-bool SurfaceFlingerConsumer::getFrameTimestamps(uint64_t frameNumber,
- FrameTimestamps* outTimestamps) const {
- sp<const Layer> l = mLayer.promote();
- return l.get() ? l->getFrameTimestamps(frameNumber, outTimestamps) : false;
+bool SurfaceFlingerConsumer::addAndGetFrameTimestamps(
+ const NewFrameEventsEntry* newTimestamps,
+ uint64_t frameNumber, FrameTimestamps *outTimestamps) {
+ sp<Layer> l = mLayer.promote();
+ if (!l.get()) {
+ return false;
+ }
+ return l->addAndGetFrameTimestamps(
+ newTimestamps, frameNumber, outTimestamps);
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index cb4c334..0f46ddc 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -37,7 +37,7 @@
};
SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
- uint32_t tex, const Layer* layer)
+ uint32_t tex, Layer* layer)
: GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false),
mTransformToDisplayInverse(false), mSurfaceDamage(), mLayer(layer)
{}
@@ -84,8 +84,9 @@
void releasePendingBuffer();
#endif
- virtual bool getFrameTimestamps(uint64_t frameNumber,
- FrameTimestamps* outTimestamps) const override;
+ virtual bool addAndGetFrameTimestamps(
+ const NewFrameEventsEntry* newTimestamps,
+ uint64_t frameNumber, FrameTimestamps* outTimestamps) override;
private:
virtual void onSidebandStreamChanged();
@@ -107,7 +108,7 @@
#endif
// The layer for this SurfaceFlingerConsumer
- wp<const Layer> mLayer;
+ const wp<Layer> mLayer;
};
// ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 0143d99..3bdb021 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -1068,12 +1068,12 @@
nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
- preComposition();
+ preComposition(refreshStartTime);
rebuildLayerStacks();
setUpHWComposer();
doDebugFlashRegions();
doComposition();
- postComposition(refreshStartTime);
+ postComposition();
}
void SurfaceFlinger::doDebugFlashRegions()
@@ -1116,13 +1116,13 @@
}
}
-void SurfaceFlinger::preComposition()
+void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
{
bool needExtraInvalidate = false;
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
- if (layers[i]->onPreComposition()) {
+ if (layers[i]->onPreComposition(refreshStartTime)) {
needExtraInvalidate = true;
}
}
@@ -1131,19 +1131,28 @@
}
}
-void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
+void SurfaceFlinger::postComposition()
{
+ const HWComposer& hwc = getHwComposer();
+ const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+
+ bool hadGlesComposition =
+ getHwComposer().hasGlesComposition(hw->getHwcDisplayId());
+ sp<Fence> glCompositionDoneFence = hadGlesComposition
+ ? hw->getClientTargetAcquireFence()
+ : Fence::NO_FENCE;
+
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
- bool frameLatched = layers[i]->onPostComposition();
+ bool frameLatched = layers[i]->onPostComposition(
+ glCompositionDoneFence);
if (frameLatched) {
recordBufferingStats(layers[i]->getName().string(),
layers[i]->getOccupancyHistory(false));
}
}
- const HWComposer& hwc = getHwComposer();
sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
if (presentFence->isValid()) {
@@ -1154,17 +1163,12 @@
}
}
- const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
if (kIgnorePresentFences) {
if (hw->isDisplayOn()) {
enableHardwareVsync();
}
}
- // The present fence is actually a retire fence in HWC1.
- mFenceTracker.addFrame(refreshStartTime, Fence::NO_FENCE, presentFence,
- hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
-
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
@@ -1932,6 +1936,7 @@
bool SurfaceFlinger::handlePageFlip()
{
+ nsecs_t latchTime = systemTime();
Region dirtyRegion;
bool visibleRegions = false;
@@ -1963,7 +1968,7 @@
}
for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
Layer* layer = layersWithQueuedFrames[i];
- const Region dirty(layer->latchBuffer(visibleRegions));
+ const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
layer->useSurfaceDamage();
const Layer::State& s(layer->getDrawingState());
invalidateLayerStack(s.layerStack, dirty);
@@ -2755,9 +2760,9 @@
}
if ((index < numArgs) &&
- (args[index] == String16("--fences"))) {
+ (args[index] == String16("--frame-events"))) {
index++;
- mFenceTracker.dump(&result);
+ dumpFrameEventsLocked(result);
dumpAll = false;
}
}
@@ -2880,6 +2885,16 @@
NUM_BUCKETS - 1, bucketTimeSec, percent);
}
+void SurfaceFlinger::dumpFrameEventsLocked(String8& result) {
+ result.appendFormat("Layer frame timestamps:\n");
+
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ currentLayers[i]->dumpFrameEvents(result);
+ }
+}
+
void SurfaceFlinger::recordBufferingStats(const char* layerName,
std::vector<OccupancyTracker::Segment>&& history) {
Mutex::Autolock lock(mBufferingStatsMutex);
@@ -3754,11 +3769,6 @@
return result;
}
-bool SurfaceFlinger::getFrameTimestamps(const Layer& layer,
- uint64_t frameNumber, FrameTimestamps* outTimestamps) {
- return mFenceTracker.getFrameTimestamps(layer, frameNumber, outTimestamps);
-}
-
void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
const sp<const DisplayDevice>& hw, uint32_t minLayerZ, uint32_t maxLayerZ) {
if (DEBUG_SCREENSHOTS) {