SF: Add FenceTracker
FenceTracker tracks all fences in SurfaceFlinger. These timestamps
could be used for debugging, profiling, or be exposed to the
application.
Change-Id: I4297a661c0a7530e744168ac7a2a66c4bca92fd5
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 8cc9fc1..d0a0401 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -10,6 +10,7 @@
DispSync.cpp \
EventControlThread.cpp \
EventThread.cpp \
+ FenceTracker.cpp \
FrameTracker.cpp \
Layer.cpp \
LayerDim.cpp \
@@ -103,7 +104,7 @@
endif
LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
-LOCAL_CFLAGS += -std=c++11
+LOCAL_CFLAGS += -std=c++14
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -133,7 +134,7 @@
LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic
LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-LOCAL_CPPFLAGS := -std=c++11
+LOCAL_CPPFLAGS := -std=c++14
LOCAL_INIT_RC := surfaceflinger.rc
@@ -172,7 +173,7 @@
LOCAL_CLANG := true
LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-LOCAL_CPPFLAGS := -std=c++11
+LOCAL_CPPFLAGS := -std=c++14
LOCAL_SRC_FILES := \
DdmConnection.cpp
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 8d8e40d..f7c8473 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -364,11 +364,9 @@
false, Transform::ROT_0);
}
-#ifdef USE_HWC2
const sp<Fence>& DisplayDevice::getClientTargetAcquireFence() const {
return mDisplaySurface->getClientTargetAcquireFence();
}
-#endif
// ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 38241d9..9ac8a97 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -49,9 +49,7 @@
struct DisplayInfo;
class DisplaySurface;
-#ifdef USE_HWC2
class Fence;
-#endif
class IGraphicBufferProducer;
class Layer;
class SurfaceFlinger;
@@ -174,9 +172,7 @@
EGLBoolean makeCurrent(EGLDisplay dpy, EGLContext ctx) const;
void setViewportAndProjection() const;
-#ifdef USE_HWC2
const sp<Fence>& getClientTargetAcquireFence() const;
-#endif
/* ------------------------------------------------------------------------
* Display power mode management.
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
index d819f83..d801bb3 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
@@ -76,9 +76,7 @@
virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0;
-#ifdef USE_HWC2
virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
-#endif
protected:
DisplaySurface() {}
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 29e0766..7368d77 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -60,15 +60,14 @@
ConsumerBase(consumer),
mDisplayType(disp),
mCurrentBufferSlot(-1),
-#ifdef USE_HWC2
mCurrentBuffer(),
mCurrentFence(Fence::NO_FENCE),
+#ifdef USE_HWC2
mHwc(hwc),
mHasPendingRelease(false),
mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
mPreviousBuffer()
#else
- mCurrentBuffer(0),
mHwc(hwc)
#endif
{
@@ -168,9 +167,7 @@
}
mCurrentBufferSlot = item.mSlot;
mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
-#ifdef USE_HWC2
mCurrentFence = item.mFence;
-#endif
outFence = item.mFence;
outBuffer = mCurrentBuffer;
@@ -254,11 +251,9 @@
ConsumerBase::dumpLocked(result, prefix);
}
-#ifdef USE_HWC2
const sp<Fence>& FramebufferSurface::getClientTargetAcquireFence() const {
return mCurrentFence;
}
-#endif
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 0605602..439435a 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -52,9 +52,7 @@
// displays.
virtual void resizeBuffers(const uint32_t /*w*/, const uint32_t /*h*/) { };
-#ifdef USE_HWC2
virtual const sp<Fence>& getClientTargetAcquireFence() const override;
-#endif
private:
virtual ~FramebufferSurface() { }; // this class cannot be overloaded
@@ -88,10 +86,8 @@
// no current buffer.
sp<GraphicBuffer> mCurrentBuffer;
-#ifdef USE_HWC2
// mCurrentFence is the current buffer's acquire fence
sp<Fence> mCurrentFence;
-#endif
// Hardware composer, owned by SurfaceFlinger.
HWComposer& mHwc;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 1afed36..ee4bf02 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -311,11 +311,9 @@
mSinkBufferHeight = h;
}
-#ifdef USE_HWC2
const sp<Fence>& VirtualDisplaySurface::getClientTargetAcquireFence() const {
return mFbFence;
}
-#endif
status_t VirtualDisplaySurface::requestBuffer(int pslot,
sp<GraphicBuffer>* outBuf) {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index fe187c2..cfa4e4c 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -90,9 +90,7 @@
virtual void onFrameCommitted();
virtual void dumpAsString(String8& result) const;
virtual void resizeBuffers(const uint32_t w, const uint32_t h);
-#ifdef USE_HWC2
virtual const sp<Fence>& getClientTargetAcquireFence() const override;
-#endif
private:
enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1};
diff --git a/services/surfaceflinger/FenceTracker.cpp b/services/surfaceflinger/FenceTracker.cpp
new file mode 100644
index 0000000..7da1d93
--- /dev/null
+++ b/services/surfaceflinger/FenceTracker.cpp
@@ -0,0 +1,186 @@
+/*
+ * 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 <inttypes.h>
+#include "FenceTracker.h"
+#include "Layer.h"
+
+namespace android {
+
+FenceTracker::FenceTracker() :
+ mFrameCounter(0),
+ mOffset(0),
+ mFrames() {}
+
+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.retireTime) {
+ outString->appendFormat("- Retire\t%" PRId64 "\n",
+ frame.retireTime);
+ } else {
+ 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("---- Posted\t%" PRId64 "\n",
+ layer.postedTime);
+ 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() {
+ for (auto& frame : mFrames) {
+ 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> retireFence,
+ const Vector<sp<Layer>>& layers, sp<Fence> glDoneFence) {
+ 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 postedTime;
+ sp<Fence> acquireFence;
+ sp<Fence> prevReleaseFence;
+ int32_t key = layers[i]->getSequence();
+
+ layers[i]->getFenceData(&name, &frameNumber, &glesComposition,
+ &postedTime, &acquireFence, &prevReleaseFence);
+#ifdef USE_HWC2
+ if (glesComposition) {
+ frame.layers.emplace(std::piecewise_construct,
+ std::forward_as_tuple(key),
+ std::forward_as_tuple(name, frameNumber, glesComposition,
+ postedTime, 0, 0, acquireFence, prevReleaseFence));
+ wasGlesCompositionDone = true;
+ } else {
+ frame.layers.emplace(std::piecewise_construct,
+ std::forward_as_tuple(key),
+ std::forward_as_tuple(name, frameNumber, glesComposition,
+ postedTime, 0, 0, acquireFence, Fence::NO_FENCE));
+
+ auto prevLayer = prevFrame.layers.find(key);
+ if (prevLayer != prevFrame.layers.end()) {
+ prevLayer->second.releaseFence = prevReleaseFence;
+ }
+ }
+#else
+ frame.layers.emplace(std::piecewise_construct,
+ std::forward_as_tuple(key),
+ std::forward_as_tuple(name, frameNumber, glesComposition,
+ postedTime, 0, 0, acquireFence,
+ glesComposition ? Fence::NO_FENCE : prevReleaseFence));
+ if (glesComposition) {
+ wasGlesCompositionDone = true;
+ }
+#endif
+ frame.layers.emplace(std::piecewise_construct,
+ std::forward_as_tuple(key),
+ std::forward_as_tuple(name, frameNumber, glesComposition,
+ postedTime, 0, 0, acquireFence, prevReleaseFence));
+ }
+
+ frame.frameId = mFrameCounter;
+ frame.refreshStartTime = refreshStartTime;
+ frame.retireTime = 0;
+ frame.glesCompositionDoneTime = 0;
+ prevFrame.retireFence = retireFence;
+ frame.retireFence = Fence::NO_FENCE;
+ frame.glesCompositionDoneFence = wasGlesCompositionDone ? glDoneFence :
+ Fence::NO_FENCE;
+
+ mOffset = (mOffset + 1) % MAX_FRAME_HISTORY;
+ mFrameCounter++;
+
+ checkFencesForCompletion();
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/FenceTracker.h b/services/surfaceflinger/FenceTracker.h
new file mode 100644
index 0000000..de99820
--- /dev/null
+++ b/services/surfaceflinger/FenceTracker.h
@@ -0,0 +1,103 @@
+/*
+ * 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;
+
+/*
+ * 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> retireFence,
+ const Vector<sp<Layer>>& layers, sp<Fence> glDoneFence);
+
+protected:
+ static constexpr size_t MAX_FRAME_HISTORY = 128;
+
+ struct LayerRecord {
+ String8 name; // layer name
+ uint64_t frameNumber; // frame number for this layer
+ bool isGlesComposition; // was GLES composition used for this layer?
+ nsecs_t postedTime; // time when buffer was queued
+ 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 postedTime,
+ nsecs_t acquireTime, nsecs_t releaseTime,
+ sp<Fence> acquireFence, sp<Fence> releaseFence) :
+ name(name), frameNumber(frameNumber),
+ isGlesComposition(isGlesComposition), postedTime(postedTime),
+ acquireTime(acquireTime), releaseTime(releaseTime),
+ acquireFence(acquireFence), releaseFence(releaseFence) {};
+ LayerRecord() : name("uninitialized"), frameNumber(0),
+ isGlesComposition(false), postedTime(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 retire fence
+ nsecs_t retireTime;
+ // timestamp from the GLES composition completion fence
+ nsecs_t glesCompositionDoneTime;
+ // 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),
+ retireTime(0), glesCompositionDoneTime(0),
+ 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 42d0810..cde92e9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -82,6 +82,9 @@
mFiltering(false),
mNeedsFiltering(false),
mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2),
+#ifndef USE_HWC2
+ mIsGlesComposition(false),
+#endif
mProtectedByApp(false),
mHasSurface(false),
mClientRef(client),
@@ -750,6 +753,7 @@
Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
layer.setVisibleRegionScreen(visible);
layer.setSurfaceDamage(surfaceDamageRegion);
+ mIsGlesComposition = (layer.getCompositionType() == HWC_FRAMEBUFFER);
if (mSidebandStream.get()) {
layer.setSidebandStream(mSidebandStream);
@@ -2046,6 +2050,23 @@
mFrameTracker.getStats(outStats);
}
+void Layer::getFenceData(String8* outName, uint64_t* outFrameNumber,
+ bool* outIsGlesComposition, nsecs_t* outPostedTime,
+ sp<Fence>* outAcquireFence, sp<Fence>* outPrevReleaseFence) const {
+ *outName = mName;
+ *outFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
+#ifdef USE_HWC2
+ *outIsGlesComposition = mHwcLayers.count(HWC_DISPLAY_PRIMARY) ?
+ mHwcLayers.at(HWC_DISPLAY_PRIMARY).compositionType ==
+ HWC2::Composition::Client : true;
+#else
+ *outIsGlesComposition = mIsGlesComposition;
+#endif
+ *outPostedTime = mSurfaceFlingerConsumer->getTimestamp();
+ *outAcquireFence = mSurfaceFlingerConsumer->getCurrentFence();
+ *outPrevReleaseFence = mSurfaceFlingerConsumer->getPrevReleaseFence();
+}
// ---------------------------------------------------------------------------
Layer::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b0088e6..d5c84b6 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -177,6 +177,8 @@
sp<IGraphicBufferProducer> getProducer() const;
const String8& getName() const;
+ int32_t getSequence() const { return sequence; }
+
// -----------------------------------------------------------------------
// Virtuals
@@ -396,6 +398,10 @@
void logFrameStats();
void getFrameStats(FrameStats* outStats) const;
+ void getFenceData(String8* outName, uint64_t* outFrameNumber,
+ bool* outIsGlesComposition, nsecs_t* outPostedTime,
+ sp<Fence>* outAcquireFence, sp<Fence>* outPrevReleaseFence) const;
+
protected:
// constant
sp<SurfaceFlinger> mFlinger;
@@ -555,6 +561,8 @@
bool clearClientTarget;
};
std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+#else
+ bool mIsGlesComposition;
#endif
// page-flip thread (currently main thread)
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3a0e21f..d1cb1be 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -910,6 +910,7 @@
void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
+ nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
static nsecs_t previousExpectedPresent = 0;
nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
static bool previousFrameMissed = false;
@@ -930,7 +931,7 @@
setUpHWComposer();
doDebugFlashRegions();
doComposition();
- postComposition();
+ postComposition(refreshStartTime);
}
// Release any buffers which were replaced this frame
@@ -999,7 +1000,7 @@
}
}
-void SurfaceFlinger::postComposition()
+void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
{
ATRACE_CALL();
ALOGV("postComposition");
@@ -1027,6 +1028,9 @@
}
}
+ mFenceTracker.addFrame(refreshStartTime, presentFence,
+ hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
+
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
@@ -2539,6 +2543,13 @@
dumpStaticScreenStats(result);
dumpAll = false;
}
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--fences"))) {
+ index++;
+ mFenceTracker.dump(&result);
+ dumpAll = false;
+ }
}
if (dumpAll) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7d6f139..37110b9 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -50,6 +50,7 @@
#include "Barrier.h"
#include "DisplayDevice.h"
#include "DispSync.h"
+#include "FenceTracker.h"
#include "FrameTracker.h"
#include "MessageQueue.h"
@@ -384,7 +385,7 @@
Region& dirtyRegion, Region& opaqueRegion);
void preComposition();
- void postComposition();
+ void postComposition(nsecs_t refreshStartTime);
void rebuildLayerStacks();
void setUpHWComposer();
void doComposition();
@@ -488,6 +489,7 @@
nsecs_t mLastTransactionTime;
bool mBootFinished;
bool mForceFullDamage;
+ FenceTracker mFenceTracker;
// these are thread safe
mutable MessageQueue mEventQueue;
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 4c80fa0..c71b3bc 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -190,6 +190,7 @@
#ifdef USE_HWC2
void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence)
{
+ mPrevReleaseFence = fence;
if (!mPendingRelease.isPending) {
GLConsumer::setReleaseFence(fence);
return;
@@ -219,8 +220,17 @@
strerror(-result), result);
mPendingRelease = PendingRelease();
}
+#else
+void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence) {
+ mPrevReleaseFence = fence;
+ GLConsumer::setReleaseFence(fence);
+}
#endif
+sp<Fence> SurfaceFlingerConsumer::getPrevReleaseFence() const {
+ return mPrevReleaseFence;
+}
+
void SurfaceFlingerConsumer::setContentsChangedListener(
const wp<ContentsChangedListener>& listener) {
setFrameAvailableListener(listener);
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index f40d53e..51b002f 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -37,7 +37,8 @@
SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
uint32_t tex)
: GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false),
- mTransformToDisplayInverse(false), mSurfaceDamage()
+ mTransformToDisplayInverse(false), mSurfaceDamage(),
+ mPrevReleaseFence(Fence::NO_FENCE)
{}
class BufferRejecter {
@@ -75,8 +76,9 @@
nsecs_t computeExpectedPresent(const DispSync& dispSync);
-#ifdef USE_HWC2
virtual void setReleaseFence(const sp<Fence>& fence) override;
+ sp<Fence> getPrevReleaseFence() const;
+#ifdef USE_HWC2
void releasePendingBuffer();
#endif
@@ -98,6 +100,9 @@
// presentDisplay
PendingRelease mPendingRelease;
#endif
+
+ // The release fence of the already displayed buffer (previous frame).
+ sp<Fence> mPrevReleaseFence;
};
// ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index d864874..6c68777 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -927,6 +927,7 @@
void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
+ nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
static nsecs_t previousExpectedPresent = 0;
nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
static bool previousFrameMissed = false;
@@ -947,7 +948,7 @@
setUpHWComposer();
doDebugFlashRegions();
doComposition();
- postComposition();
+ postComposition(refreshStartTime);
}
previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0);
@@ -1008,7 +1009,7 @@
}
}
-void SurfaceFlinger::postComposition()
+void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
{
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
@@ -1034,6 +1035,9 @@
}
}
+ mFenceTracker.addFrame(refreshStartTime, presentFence,
+ hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence());
+
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
@@ -2577,6 +2581,13 @@
dumpStaticScreenStats(result);
dumpAll = false;
}
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--fences"))) {
+ index++;
+ mFenceTracker.dump(&result);
+ dumpAll = false;
+ }
}
if (dumpAll) {