diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/surfaceflinger/Android.mk | 3 | ||||
-rw-r--r-- | services/surfaceflinger/DispSync.cpp | 117 | ||||
-rw-r--r-- | services/surfaceflinger/DispSync.h | 22 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 46 |
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; } } |