summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ady Abraham <adyabr@google.com> 2021-03-31 16:56:03 -0700
committer Ady Abraham <adyabr@google.com> 2021-04-02 22:30:12 +0000
commit6c1b7aca75e3fb0d45789b15007202493de6bc3d (patch)
tree33e2216ceb207348dad96465d653082b487547ec
parentd043c248649e8e9b51c73b6d3c02257882149dcc (diff)
SF: use FenceTime when possible
Fence::getSignalTime is calling a system call everytime, where FenceTime caches the signal time. This shows reduction in simpleperf for the main thread 2.23% -> 1.25% Test: simpleperf for PIP + Notification shade expansion Bug: 184378996 Change-Id: I182db2ddfcb7fdbde758f5d87357a16e60c1bb07
-rw-r--r--libs/ui/FenceTime.cpp28
-rw-r--r--libs/ui/include/ui/FenceTime.h7
-rw-r--r--services/surfaceflinger/BufferStateLayer.cpp9
-rw-r--r--services/surfaceflinger/FrameTracker.cpp5
-rw-r--r--services/surfaceflinger/FrameTracker.h2
-rw-r--r--services/surfaceflinger/Layer.cpp3
-rw-r--r--services/surfaceflinger/Layer.h1
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp41
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h9
9 files changed, 75 insertions, 30 deletions
diff --git a/libs/ui/FenceTime.cpp b/libs/ui/FenceTime.cpp
index bdfe04b0dd..538c1d2a42 100644
--- a/libs/ui/FenceTime.cpp
+++ b/libs/ui/FenceTime.cpp
@@ -97,6 +97,34 @@ bool FenceTime::isValid() const {
return mState != State::INVALID;
}
+status_t FenceTime::wait(int timeout) {
+ // See if we already have a cached value we can return.
+ nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
+ if (signalTime != Fence::SIGNAL_TIME_PENDING) {
+ return NO_ERROR;
+ }
+
+ // Hold a reference to the fence on the stack in case the class'
+ // reference is removed by another thread. This prevents the
+ // fence from being destroyed until the end of this method, where
+ // we conveniently do not have the lock held.
+ sp<Fence> fence;
+ {
+ // With the lock acquired this time, see if we have the cached
+ // value or if we need to poll the fence.
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mFence.get()) {
+ // Another thread set the signal time just before we added the
+ // reference to mFence.
+ return NO_ERROR;
+ }
+ fence = mFence;
+ }
+
+ // Make the system call without the lock held.
+ return fence->wait(timeout);
+}
+
nsecs_t FenceTime::getSignalTime() {
// See if we already have a cached value we can return.
nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
diff --git a/libs/ui/include/ui/FenceTime.h b/libs/ui/include/ui/FenceTime.h
index ecba7f73e8..ac75f431a0 100644
--- a/libs/ui/include/ui/FenceTime.h
+++ b/libs/ui/include/ui/FenceTime.h
@@ -112,6 +112,13 @@ public:
// Returns a snapshot of the FenceTime in its current state.
Snapshot getSnapshot() const;
+ // wait waits for up to timeout milliseconds for the fence to signal. If
+ // the fence signals then NO_ERROR is returned. If the timeout expires
+ // before the fence signals then -ETIME is returned. A timeout of
+ // TIMEOUT_NEVER may be used to indicate that the call should wait
+ // indefinitely for the fence to signal.
+ status_t wait(int timeout);
+
void signalForTest(nsecs_t signalTime);
private:
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index a974dc4488..d6becbf213 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -432,10 +432,12 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence
}
bool BufferStateLayer::setAcquireFence(const sp<Fence>& fence) {
+ mCurrentState.acquireFence = fence;
+ mCurrentState.acquireFenceTime = std::make_unique<FenceTime>(fence);
+
// The acquire fences of BufferStateLayers have already signaled before they are set
- mCallbackHandleAcquireTime = fence->getSignalTime();
+ mCallbackHandleAcquireTime = mCurrentState.acquireFenceTime->getSignalTime();
- mCurrentState.acquireFence = fence;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
@@ -691,7 +693,8 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse
// bufferSurfaceFrame could be seen here if a pending state was applied successfully and we
// are processing the next state.
addSurfaceFramePresentedForBuffer(bufferSurfaceFrame,
- mDrawingState.acquireFence->getSignalTime(), latchTime);
+ mDrawingState.acquireFenceTime->getSignalTime(),
+ latchTime);
}
mCurrentStateModified = false;
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index 8ad805b1d8..178c531a2a 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -62,10 +62,9 @@ void FrameTracker::setActualPresentTime(nsecs_t presentTime) {
mFrameRecords[mOffset].actualPresentTime = presentTime;
}
-void FrameTracker::setActualPresentFence(
- std::shared_ptr<FenceTime>&& readyFence) {
+void FrameTracker::setActualPresentFence(const std::shared_ptr<FenceTime>& readyFence) {
Mutex::Autolock lock(mMutex);
- mFrameRecords[mOffset].actualPresentFence = std::move(readyFence);
+ mFrameRecords[mOffset].actualPresentFence = readyFence;
mNumFences++;
}
diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h
index 35382be1c0..bc412aee2f 100644
--- a/services/surfaceflinger/FrameTracker.h
+++ b/services/surfaceflinger/FrameTracker.h
@@ -66,7 +66,7 @@ public:
// setActualPresentFence sets the fence that is used to get the time
// at which the current frame became visible to the user.
- void setActualPresentFence(std::shared_ptr<FenceTime>&& fence);
+ void setActualPresentFence(const std::shared_ptr<FenceTime>& fence);
// setDisplayRefreshPeriod sets the display refresh period in nanoseconds.
// This is used to compute frame presentation duration statistics relative
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b5410fe295..dbd6b32656 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -116,7 +116,8 @@ Layer::Layer(const LayerCreationArgs& args)
mCurrentState.bufferTransform = 0;
mCurrentState.transformToDisplayInverse = false;
mCurrentState.crop.makeInvalid();
- mCurrentState.acquireFence = new Fence(-1);
+ mCurrentState.acquireFence = sp<Fence>::make(-1);
+ mCurrentState.acquireFenceTime = std::make_shared<FenceTime>(mCurrentState.acquireFence);
mCurrentState.dataspace = ui::Dataspace::UNKNOWN;
mCurrentState.hdrMetadata.validTypes = 0;
mCurrentState.surfaceDamageRegion = Region::INVALID_REGION;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 421a10776f..3f7a75f691 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -261,6 +261,7 @@ public:
sp<GraphicBuffer> buffer;
client_cache_t clientCacheId;
sp<Fence> acquireFence;
+ std::shared_ptr<FenceTime> acquireFenceTime;
HdrMetadata hdrMetadata;
Region surfaceDamageRegion;
int32_t api;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 84b4b236db..a9c82d0333 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1661,7 +1661,7 @@ void SurfaceFlinger::setVsyncEnabled(bool enabled) {
}));
}
-sp<Fence> SurfaceFlinger::previousFrameFence() {
+SurfaceFlinger::FenceWithFenceTime SurfaceFlinger::previousFrameFence() {
// We are storing the last 2 present fences. If sf's phase offset is to be
// woken up before the actual vsync but targeting the next vsync, we need to check
// fence N-2
@@ -1671,9 +1671,9 @@ sp<Fence> SurfaceFlinger::previousFrameFence() {
bool SurfaceFlinger::previousFramePending(int graceTimeMs) {
ATRACE_CALL();
- const sp<Fence>& fence = previousFrameFence();
+ const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime;
- if (fence == Fence::NO_FENCE) {
+ if (fence == FenceTime::NO_FENCE) {
return false;
}
@@ -1684,9 +1684,9 @@ bool SurfaceFlinger::previousFramePending(int graceTimeMs) {
}
nsecs_t SurfaceFlinger::previousFramePresentTime() {
- const sp<Fence>& fence = previousFrameFence();
+ const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime;
- if (fence == Fence::NO_FENCE) {
+ if (fence == FenceTime::NO_FENCE) {
return Fence::SIGNAL_TIME_INVALID;
}
@@ -2117,16 +2117,17 @@ void SurfaceFlinger::postComposition() {
getBE().mDisplayTimeline.updateSignalTimes();
mPreviousPresentFences[1] = mPreviousPresentFences[0];
- mPreviousPresentFences[0] =
+ mPreviousPresentFences[0].fence =
display ? getHwComposer().getPresentFence(display->getPhysicalId()) : Fence::NO_FENCE;
- auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]);
- getBE().mDisplayTimeline.push(presentFenceTime);
+ mPreviousPresentFences[0].fenceTime =
+ std::make_shared<FenceTime>(mPreviousPresentFences[0].fence);
+
+ getBE().mDisplayTimeline.push(mPreviousPresentFences[0].fenceTime);
// Set presentation information before calling Layer::releasePendingBuffer, such that jank
// information from previous' frame classification is already available when sending jank info
// to clients, so they get jank classification as early as possible.
- mFrameTimeline->setSfPresent(systemTime(),
- std::make_shared<FenceTime>(mPreviousPresentFences[0]),
+ mFrameTimeline->setSfPresent(systemTime(), mPreviousPresentFences[0].fenceTime,
glCompositionDoneFenceTime != FenceTime::NO_FENCE);
nsecs_t dequeueReadyTime = systemTime();
@@ -2140,7 +2141,7 @@ void SurfaceFlinger::postComposition() {
// be sampled a little later than when we started doing work for this frame,
// but that should be okay since updateCompositorTiming has snapping logic.
updateCompositorTiming(stats, mCompositionEngine->getLastFrameRefreshTimestamp(),
- presentFenceTime);
+ mPreviousPresentFences[0].fenceTime);
CompositorTiming compositorTiming;
{
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
@@ -2148,8 +2149,9 @@ void SurfaceFlinger::postComposition() {
}
mDrawingState.traverse([&](Layer* layer) {
- const bool frameLatched = layer->onPostComposition(display, glCompositionDoneFenceTime,
- presentFenceTime, compositorTiming);
+ const bool frameLatched =
+ layer->onPostComposition(display, glCompositionDoneFenceTime,
+ mPreviousPresentFences[0].fenceTime, compositorTiming);
if (frameLatched) {
recordBufferingStats(layer->getName(), layer->getOccupancyHistory(false));
}
@@ -2162,12 +2164,12 @@ void SurfaceFlinger::postComposition() {
}
}
- mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0]);
+ mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence);
mTransactionCallbackInvoker.sendCallbacks();
if (display && display->isPrimary() && display->getPowerMode() == hal::PowerMode::ON &&
- presentFenceTime->isValid()) {
- mScheduler->addPresentFence(presentFenceTime);
+ mPreviousPresentFences[0].fenceTime->isValid()) {
+ mScheduler->addPresentFence(mPreviousPresentFences[0].fenceTime);
}
const bool isDisplayConnected =
@@ -2182,9 +2184,8 @@ void SurfaceFlinger::postComposition() {
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
- if (presentFenceTime->isValid()) {
- mAnimFrameTracker.setActualPresentFence(
- std::move(presentFenceTime));
+ if (mPreviousPresentFences[0].fenceTime->isValid()) {
+ mAnimFrameTracker.setActualPresentFence(mPreviousPresentFences[0].fenceTime);
} else if (isDisplayConnected) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
@@ -2203,7 +2204,7 @@ void SurfaceFlinger::postComposition() {
mTimeStats->incrementClientCompositionReusedFrames();
}
- mTimeStats->setPresentFenceGlobal(presentFenceTime);
+ mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime);
const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle);
const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c57b180dd4..c4c9ce3c20 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1013,9 +1013,14 @@ private:
bool isDisplayModeAllowed(DisplayModeId) const REQUIRES(mStateLock);
+ struct FenceWithFenceTime {
+ sp<Fence> fence = Fence::NO_FENCE;
+ std::shared_ptr<FenceTime> fenceTime = FenceTime::NO_FENCE;
+ };
+
// Gets the fence for the previous frame.
// Must be called on the main thread.
- sp<Fence> previousFrameFence();
+ FenceWithFenceTime previousFrameFence();
// Whether the previous frame has not yet been presented to the display.
// If graceTimeMs is positive, this method waits for at most the provided
@@ -1193,7 +1198,7 @@ private:
std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> mLayersWithQueuedFrames;
// Tracks layers that need to update a display's dirty region.
std::vector<sp<Layer>> mLayersPendingRefresh;
- std::array<sp<Fence>, 2> mPreviousPresentFences = {Fence::NO_FENCE, Fence::NO_FENCE};
+ std::array<FenceWithFenceTime, 2> mPreviousPresentFences;
// True if in the previous frame at least one layer was composed via the GPU.
bool mHadClientComposition = false;
// True if in the previous frame at least one layer was composed via HW Composer.