summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/surfaceflinger/Android.mk3
-rw-r--r--services/surfaceflinger/DispSync.cpp117
-rw-r--r--services/surfaceflinger/DispSync.h22
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp46
4 files changed, 91 insertions, 97 deletions
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 0834c80..56c539f 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -37,9 +37,6 @@ LOCAL_SRC_FILES:= \
LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-ifeq ($(TARGET_BOARD_PLATFORM),omap3)
- LOCAL_CFLAGS += -DNO_RGBX_8888
-endif
ifeq ($(TARGET_BOARD_PLATFORM),omap4)
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
endif
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index d771e2c..12da9a5 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -37,34 +37,23 @@ namespace android {
// Setting this to true enables verbose tracing that can be used to debug
// vsync event model or phase issues.
-static const bool traceDetailedInfo = false;
+static const bool kTraceDetailedInfo = false;
// This is the threshold used to determine when hardware vsync events are
// needed to re-synchronize the software vsync model with the hardware. The
// error metric used is the mean of the squared difference between each
// present time and the nearest software-predicted vsync.
-static const nsecs_t errorThreshold = 160000000000;
-
-// This works around the lack of support for the sync framework on some
-// devices.
-#ifdef RUNNING_WITHOUT_SYNC_FRAMEWORK
-static const bool runningWithoutSyncFramework = true;
-#else
-static const bool runningWithoutSyncFramework = false;
-#endif
+static const nsecs_t kErrorThreshold = 160000000000; // 400 usec squared
// This is the offset from the present fence timestamps to the corresponding
// vsync event.
-static const int64_t presentTimeOffset = PRESENT_TIME_OFFSET_FROM_VSYNC_NS;
+static const int64_t kPresentTimeOffset = PRESENT_TIME_OFFSET_FROM_VSYNC_NS;
class DispSyncThread: public Thread {
public:
DispSyncThread():
- mLowPowerMode(false),
mStop(false),
- mLastVsyncSent(false),
- mLastBufferFull(false),
mPeriod(0),
mPhase(0),
mWakeupLatency(0) {
@@ -138,7 +127,7 @@ public:
// Don't correct by more than 500 us
mWakeupLatency = 500000;
}
- if (traceDetailedInfo) {
+ if (kTraceDetailedInfo) {
ATRACE_INT64("DispSync:WakeupLat", now - nextEventTime);
ATRACE_INT64("DispSync:AvgWakeupLat", mWakeupLatency);
}
@@ -148,18 +137,7 @@ public:
}
if (callbackInvocations.size() > 0) {
- if (mLowPowerMode) {
- if (!mLastVsyncSent || !mLastBufferFull) {
- fireCallbackInvocations(callbackInvocations);
- mLastVsyncSent = true;
- } else
- mLastVsyncSent = false;
- } else {
- fireCallbackInvocations(callbackInvocations);
- }
- mLastBufferFull = true;
- } else {
- mLastBufferFull = false;
+ fireCallbackInvocations(callbackInvocations);
}
}
@@ -207,14 +185,12 @@ public:
return BAD_VALUE;
}
- // This method is only here to handle the runningWithoutSyncFramework
- // case.
+ // This method is only here to handle the kIgnorePresentFences case.
bool hasAnyEventListeners() {
Mutex::Autolock lock(mMutex);
return !mEventListeners.empty();
}
- bool mLowPowerMode;
private:
struct EventListener {
@@ -287,8 +263,6 @@ private:
}
bool mStop;
- bool mLastVsyncSent;
- bool mLastBufferFull;
nsecs_t mPeriod;
nsecs_t mPhase;
@@ -313,19 +287,22 @@ private:
bool mParity;
};
-DispSync::DispSync() {
- mThread = new DispSyncThread();
+DispSync::DispSync() :
+ mRefreshSkipCount(0),
+ mThread(new DispSyncThread()) {
+
mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
reset();
beginResync();
- if (traceDetailedInfo) {
- // If runningWithoutSyncFramework is true then the ZeroPhaseTracer
+ if (kTraceDetailedInfo) {
+ // If we're not getting present fences then the ZeroPhaseTracer
// would prevent HW vsync event from ever being turned off.
- // Furthermore the zero-phase tracing is not needed because any time
- // there is an event registered we will turn on the HW vsync events.
- if (!runningWithoutSyncFramework) {
+ // Even if we're just ignoring the fences, the zero-phase tracing is
+ // not needed because any time there is an event registered we will
+ // turn on the HW vsync events.
+ if (!kIgnorePresentFences) {
addEventListener(0, new ZeroPhaseTracer());
}
}
@@ -356,14 +333,14 @@ bool DispSync::addPresentFence(const sp<Fence>& fence) {
nsecs_t t = f->getSignalTime();
if (t < INT64_MAX) {
mPresentFences[i].clear();
- mPresentTimes[i] = t + presentTimeOffset;
+ mPresentTimes[i] = t + kPresentTimeOffset;
}
}
}
updateErrorLocked();
- return mPeriod == 0 || mError > errorThreshold;
+ return mPeriod == 0 || mError > kErrorThreshold;
}
void DispSync::beginResync() {
@@ -390,7 +367,7 @@ bool DispSync::addResyncSample(nsecs_t timestamp) {
resetErrorLocked();
}
- if (runningWithoutSyncFramework) {
+ if (kIgnorePresentFences) {
// If we don't have the sync framework we will never have
// addPresentFence called. This means we have no way to know whether
// or not we're synchronized with the HW vsyncs, so we just request
@@ -399,7 +376,7 @@ bool DispSync::addResyncSample(nsecs_t timestamp) {
return mThread->hasAnyEventListeners();
}
- return mPeriod == 0 || mError > errorThreshold;
+ return mPeriod == 0 || mError > kErrorThreshold;
}
void DispSync::endResync() {
@@ -412,8 +389,11 @@ status_t DispSync::addEventListener(nsecs_t phase,
return mThread->addEventListener(phase, callback);
}
-void DispSync::setLowPowerMode(bool enabled) {
- mThread->mLowPowerMode = enabled;
+void DispSync::setRefreshSkipCount(int count) {
+ Mutex::Autolock lock(mMutex);
+ ALOGD("setRefreshSkipCount(%d)", count);
+ mRefreshSkipCount = count;
+ updateModelLocked();
}
status_t DispSync::removeEventListener(const sp<Callback>& callback) {
@@ -459,11 +439,14 @@ void DispSync::updateModelLocked() {
mPhase += mPeriod;
}
- if (traceDetailedInfo) {
+ if (kTraceDetailedInfo) {
ATRACE_INT64("DispSync:Period", mPeriod);
ATRACE_INT64("DispSync:Phase", mPhase);
}
+ // Artificially inflate the period if requested.
+ mPeriod += mPeriod * mRefreshSkipCount;
+
mThread->updateModel(mPeriod, mPhase);
}
}
@@ -473,15 +456,19 @@ void DispSync::updateErrorLocked() {
return;
}
+ // Need to compare present fences against the un-adjusted refresh period,
+ // since they might arrive between two events.
+ nsecs_t period = mPeriod / (1 + mRefreshSkipCount);
+
int numErrSamples = 0;
nsecs_t sqErrSum = 0;
for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
nsecs_t sample = mPresentTimes[i];
if (sample > mPhase) {
- nsecs_t sampleErr = (sample - mPhase) % mPeriod;
- if (sampleErr > mPeriod / 2) {
- sampleErr -= mPeriod;
+ nsecs_t sampleErr = (sample - mPhase) % period;
+ if (sampleErr > period / 2) {
+ sampleErr -= period;
}
sqErrSum += sampleErr * sampleErr;
numErrSamples++;
@@ -494,7 +481,7 @@ void DispSync::updateErrorLocked() {
mError = 0;
}
- if (traceDetailedInfo) {
+ if (kTraceDetailedInfo) {
ATRACE_INT64("DispSync:Error", mError);
}
}
@@ -516,13 +503,16 @@ nsecs_t DispSync::computeNextRefresh(int periodOffset) const {
void DispSync::dump(String8& result) const {
Mutex::Autolock lock(mMutex);
- result.appendFormat("mPeriod: %"PRId64" ns\n", mPeriod);
- result.appendFormat("mPhase: %"PRId64" ns\n", mPhase);
- result.appendFormat("mError: %"PRId64" ns (sqrt: %.1f)\n",
+ result.appendFormat("present fences are %s\n",
+ kIgnorePresentFences ? "ignored" : "used");
+ result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n",
+ mPeriod, 1000000000.0 / mPeriod, mRefreshSkipCount);
+ result.appendFormat("mPhase: %" PRId64 " ns\n", mPhase);
+ result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n",
mError, sqrt(mError));
- result.appendFormat("mNumResyncSamplesSincePresent: %d (max %d)\n",
+ result.appendFormat("mNumResyncSamplesSincePresent: %d (limit %d)\n",
mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT);
- result.appendFormat("mNumResyncSamples: %d (max %d)\n",
+ result.appendFormat("mNumResyncSamples: %zd (max %d)\n",
mNumResyncSamples, MAX_RESYNC_SAMPLES);
result.appendFormat("mResyncSamples:\n");
@@ -531,9 +521,9 @@ void DispSync::dump(String8& result) const {
size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
nsecs_t sampleTime = mResyncSamples[idx];
if (i == 0) {
- result.appendFormat(" %"PRId64"\n", sampleTime);
+ result.appendFormat(" %" PRId64 "\n", sampleTime);
} else {
- result.appendFormat(" %"PRId64" (+%"PRId64")\n",
+ result.appendFormat(" %" PRId64 " (+%" PRId64 ")\n",
sampleTime, sampleTime - previous);
}
previous = sampleTime;
@@ -541,6 +531,7 @@ void DispSync::dump(String8& result) const {
result.appendFormat("mPresentFences / mPresentTimes [%d]:\n",
NUM_PRESENT_SAMPLES);
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
previous = 0;
for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
size_t idx = (i + mPresentSampleOffset) % NUM_PRESENT_SAMPLES;
@@ -548,15 +539,21 @@ void DispSync::dump(String8& result) const {
nsecs_t presentTime = mPresentTimes[idx];
if (!signaled) {
result.appendFormat(" [unsignaled fence]\n");
+ } else if (presentTime == 0) {
+ result.appendFormat(" 0\n");
} else if (previous == 0) {
- result.appendFormat(" %"PRId64"\n", presentTime);
+ result.appendFormat(" %" PRId64 " (%.3f ms ago)\n", presentTime,
+ (now - presentTime) / 1000000.0);
} else {
- result.appendFormat(" %"PRId64" (+%"PRId64" / %.3f)\n",
+ result.appendFormat(" %" PRId64 " (+%" PRId64 " / %.3f) (%.3f ms ago)\n",
presentTime, presentTime - previous,
- (presentTime - previous) / (double) mPeriod);
+ (presentTime - previous) / (double) mPeriod,
+ (now - presentTime) / 1000000.0);
}
previous = presentTime;
}
+
+ result.appendFormat("current monotonic time: %" PRId64 "\n", now);
}
} // namespace android
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index a33ce5d..7a26df3 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -25,6 +25,18 @@
namespace android {
+// Ignore present (retire) fences if the device doesn't have support for the
+// sync framework, or if all phase offsets are zero. The latter is useful
+// because it allows us to avoid resync bursts on devices that don't need
+// phase-offset VSYNC events.
+#if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK) || \
+ (VSYNC_EVENT_PHASE_OFFSET_NS == 0 && SF_VSYNC_EVENT_PHASE_OFFSET_NS == 0)
+static const bool kIgnorePresentFences = true;
+#else
+static const bool kIgnorePresentFences = false;
+#endif
+
+
class String8;
class Fence;
class DispSyncThread;
@@ -55,6 +67,7 @@ public:
DispSync();
~DispSync();
+ // reset clears the resync samples and error value.
void reset();
// addPresentFence adds a fence for use in validating the current vsync
@@ -88,8 +101,11 @@ public:
// turned on. It should NOT be used after that.
void setPeriod(nsecs_t period);
- // Setting the low power mode reduces the frame rate to half of the default
- void setLowPowerMode(bool enabled);
+ // setRefreshSkipCount specifies an additional number of refresh
+ // cycles to skip. For example, on a 60Hz display, a skip count of 1
+ // will result in events happening at 30Hz. Default is zero. The idea
+ // is to sacrifice smoothness for battery life.
+ void setRefreshSkipCount(int count);
// addEventListener registers a callback to be called repeatedly at the
// given phase offset from the hardware vsync events. The callback is
@@ -149,6 +165,8 @@ private:
nsecs_t mPresentTimes[NUM_PRESENT_SAMPLES];
size_t mPresentSampleOffset;
+ int mRefreshSkipCount;
+
// mThread is the thread from which all the callbacks are called.
sp<DispSyncThread> mThread;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7152f93..9111dbb 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -88,14 +88,6 @@ EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint na
namespace android {
-// This works around the lack of support for the sync framework on some
-// devices.
-#ifdef RUNNING_WITHOUT_SYNC_FRAMEWORK
-static const bool runningWithoutSyncFramework = true;
-#else
-static const bool runningWithoutSyncFramework = false;
-#endif
-
// This is the phase offset in nanoseconds of the software vsync event
// relative to the vsync event reported by HWComposer. The software vsync
// event is when SurfaceFlinger and Choreographer-based applications run each
@@ -322,10 +314,13 @@ void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
class DispSyncSource : public VSyncSource, private DispSync::Callback {
public:
- DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync) :
+ DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
+ const char* label) :
mValue(0),
mPhaseOffset(phaseOffset),
mTraceVsync(traceVsync),
+ mVsyncOnLabel(String8::format("VsyncOn-%s", label)),
+ mVsyncEventLabel(String8::format("VSYNC-%s", label)),
mDispSync(dispSync) {}
virtual ~DispSyncSource() {}
@@ -340,7 +335,7 @@ public:
ALOGE("error registering vsync callback: %s (%d)",
strerror(-err), err);
}
- ATRACE_INT("VsyncOn", 1);
+ //ATRACE_INT(mVsyncOnLabel.string(), 1);
} else {
status_t err = mDispSync->removeEventListener(
static_cast<DispSync::Callback*>(this));
@@ -348,7 +343,7 @@ public:
ALOGE("error unregistering vsync callback: %s (%d)",
strerror(-err), err);
}
- ATRACE_INT("VsyncOn", 0);
+ //ATRACE_INT(mVsyncOnLabel.string(), 0);
}
}
@@ -366,7 +361,7 @@ private:
if (mTraceVsync) {
mValue = (mValue + 1) % 2;
- ATRACE_INT("VSYNC", mValue);
+ ATRACE_INT(mVsyncEventLabel.string(), mValue);
}
}
@@ -379,6 +374,8 @@ private:
const nsecs_t mPhaseOffset;
const bool mTraceVsync;
+ const String8 mVsyncOnLabel;
+ const String8 mVsyncEventLabel;
DispSync* mDispSync;
sp<VSyncSource::Callback> mCallback;
@@ -449,10 +446,10 @@ void SurfaceFlinger::init() {
// start the EventThread
sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
- vsyncPhaseOffsetNs, true);
+ vsyncPhaseOffsetNs, true, "app");
mEventThread = new EventThread(vsyncSrc);
sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
- sfVsyncPhaseOffsetNs, false);
+ sfVsyncPhaseOffsetNs, true, "sf");
mSFEventThread = new EventThread(sfVsyncSrc);
mEventQueue.setEventThread(mSFEventThread);
@@ -858,7 +855,7 @@ void SurfaceFlinger::postComposition()
}
}
- if (runningWithoutSyncFramework) {
+ if (kIgnorePresentFences) {
const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
if (hw->isScreenAcquired()) {
enableHardwareVsync();
@@ -2005,19 +2002,10 @@ status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
format = PIXEL_FORMAT_RGBA_8888;
break;
case PIXEL_FORMAT_OPAQUE:
-#ifdef NO_RGBX_8888
- format = PIXEL_FORMAT_RGB_565;
-#else
format = PIXEL_FORMAT_RGBX_8888;
-#endif
break;
}
-#ifdef NO_RGBX_8888
- if (format == PIXEL_FORMAT_RGBX_8888)
- format = PIXEL_FORMAT_RGBA_8888;
-#endif
-
*outLayer = new Layer(this, client, name, w, h, flags);
status_t err = (*outLayer)->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
@@ -2348,9 +2336,6 @@ void SurfaceFlinger::logFrameStats() {
{
static const char* config =
" [sf"
-#ifdef NO_RGBX_8888
- " NO_RGBX_8888"
-#endif
#ifdef HAS_CONTEXT_PRIORITY
" HAS_CONTEXT_PRIORITY"
#endif
@@ -2685,11 +2670,8 @@ status_t SurfaceFlinger::onTransact(
// This is an experimental interface
// Needs to be shifted to proper binder interface when we productize
case 1016: {
- mPrimaryDispSync.setLowPowerMode(true);
- return NO_ERROR;
- }
- case 1017: {
- mPrimaryDispSync.setLowPowerMode(false);
+ n = data.readInt32();
+ mPrimaryDispSync.setRefreshSkipCount(n);
return NO_ERROR;
}
}