Merge "[SurfaceFlinger] support EGLImage management in BLAST" into qt-surfaceflinger-dev
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index bd0b55f..d685366 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -143,7 +143,7 @@
}
Mutex::Autolock lock(mQueueItemLock);
- return mQueueItems[0].mTimestamp <= mFlinger->mScheduler->expectedPresentTime();
+ return mQueueItems[0].mTimestamp <= mFlinger->getExpectedPresentTime();
}
nsecs_t BufferQueueLayer::getDesiredPresentTime() {
@@ -201,7 +201,7 @@
uint64_t frameNumber = mQueueItems[0].mFrameNumber;
// The head of the queue will be dropped if there are signaled and timely frames behind it
- nsecs_t expectedPresentTime = mFlinger->mScheduler->expectedPresentTime();
+ nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime();
if (isRemovedFromCurrentState()) {
expectedPresentTime = 0;
@@ -279,7 +279,7 @@
getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
getTransformToDisplayInverse(), mFreezeGeometryUpdates);
- nsecs_t expectedPresentTime = mFlinger->mScheduler->expectedPresentTime();
+ nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime();
if (isRemovedFromCurrentState()) {
expectedPresentTime = 0;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index bcc9915..2abc1a7 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -374,7 +374,7 @@
return true;
}
- return mDesiredPresentTime <= mFlinger->mScheduler->expectedPresentTime();
+ return mDesiredPresentTime <= mFlinger->getExpectedPresentTime();
}
nsecs_t BufferStateLayer::getDesiredPresentTime() {
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 95ff9d0..81be372 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -92,7 +92,6 @@
mPeriod = period;
if (!mModelLocked && referenceTimeChanged) {
for (auto& eventListener : mEventListeners) {
- eventListener.mHasFired = false;
eventListener.mLastEventTime =
mReferenceTime - mPeriod + mPhase + eventListener.mPhase;
}
@@ -123,13 +122,6 @@
void unlockModel() {
Mutex::Autolock lock(mMutex);
- if (mModelLocked) {
- for (auto& eventListener : mEventListeners) {
- if (eventListener.mLastEventTime > mReferenceTime) {
- eventListener.mHasFired = true;
- }
- }
- }
mModelLocked = false;
ATRACE_INT("DispSync:ModelLocked", mModelLocked);
}
@@ -259,10 +251,6 @@
listener.mLastCallbackTime = lastCallbackTime;
}
- if (!mModelLocked && listener.mLastEventTime > mReferenceTime) {
- listener.mHasFired = true;
- }
-
mEventListeners.push_back(listener);
mCond.signal();
@@ -300,12 +288,8 @@
// new offset to allow for a seamless offset change without double-firing or
// skipping.
nsecs_t diff = oldPhase - phase;
- if (diff > mPeriod / 2) {
- diff -= mPeriod;
- } else if (diff < -mPeriod / 2) {
- diff += mPeriod;
- }
eventListener.mLastEventTime -= diff;
+ eventListener.mLastCallbackTime -= diff;
mCond.signal();
return NO_ERROR;
}
@@ -320,7 +304,6 @@
nsecs_t mLastEventTime;
nsecs_t mLastCallbackTime;
DispSync::Callback* mCallback;
- bool mHasFired = false;
};
struct CallbackInvocation {
@@ -368,12 +351,7 @@
eventListener.mName);
continue;
}
- if (eventListener.mHasFired && !mModelLocked) {
- eventListener.mLastEventTime = t;
- ALOGV("[%s] [%s] Skipping event due to already firing", mName,
- eventListener.mName);
- continue;
- }
+
CallbackInvocation ci;
ci.mCallback = eventListener.mCallback;
ci.mEventTime = t;
@@ -382,7 +360,6 @@
callbackInvocations.push_back(ci);
eventListener.mLastEventTime = t;
eventListener.mLastCallbackTime = now;
- eventListener.mHasFired = true;
}
}
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 00948ae..265b8aa 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -27,14 +27,16 @@
namespace android {
-DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
+DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset,
+ nsecs_t offsetThresholdForNextVsync, bool traceVsync,
const char* name)
: mName(name),
mTraceVsync(traceVsync),
mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)),
mDispSync(dispSync),
- mPhaseOffset(phaseOffset) {}
+ mPhaseOffset(phaseOffset),
+ mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {}
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
@@ -64,15 +66,15 @@
void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) {
std::lock_guard lock(mVsyncMutex);
-
- // Normalize phaseOffset to [0, period)
- auto period = mDispSync->getPeriod();
- phaseOffset %= period;
- if (phaseOffset < 0) {
- // If we're here, then phaseOffset is in (-period, 0). After this
- // operation, it will be in (0, period)
- phaseOffset += period;
+ const nsecs_t period = mDispSync->getPeriod();
+ // Check if offset should be handled as negative
+ if (phaseOffset >= mOffsetThresholdForNextVsync) {
+ phaseOffset -= period;
}
+
+ // Normalize phaseOffset to [-period, period)
+ const int numPeriods = phaseOffset / period;
+ phaseOffset -= numPeriods * period;
mPhaseOffset = phaseOffset;
// If we're not enabled, we don't need to mess with the listeners
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 4759699..b6785c5 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -25,7 +25,8 @@
class DispSyncSource final : public VSyncSource, private DispSync::Callback {
public:
- DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name);
+ DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, nsecs_t offsetThresholdForNextVsync,
+ bool traceVsync, const char* name);
~DispSyncSource() override = default;
@@ -53,6 +54,7 @@
std::mutex mVsyncMutex;
nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex);
+ const nsecs_t mOffsetThresholdForNextVsync;
bool mEnabled GUARDED_BY(mVsyncMutex) = false;
};
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 1db43a3..e762af3 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -173,5 +173,18 @@
}
}
+void LayerHistory::clearHistory() {
+ std::lock_guard lock(mLock);
+
+ auto it = mActiveLayerInfos.begin();
+ while (it != mActiveLayerInfos.end()) {
+ auto id = it->first;
+ auto layerInfo = it->second;
+ layerInfo->clearHistory();
+ mInactiveLayerInfos.insert({id, layerInfo});
+ it = mActiveLayerInfos.erase(it);
+ }
+}
+
} // namespace scheduler
} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index adc5ce5..2569b46 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -64,6 +64,9 @@
// layers. See go/content-fps-detection-in-scheduler for more information.
std::pair<float, bool> getDesiredRefreshRateAndHDR();
+ // Clears all layer history.
+ void clearHistory();
+
// Removes the handle and the object from the map.
void destroyLayer(const int64_t id);
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 95d7d31..49194f9 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -43,7 +43,8 @@
// Ignore time diff that are too high - those are stale values
if (timeDiff > TIME_EPSILON_NS.count()) return;
const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration;
- mRefreshRateHistory.insertRefreshRate(refreshDuration);
+ const int fps = 1e9f / refreshDuration;
+ mRefreshRateHistory.insertRefreshRate(fps);
}
} // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 02b6aef..f08fa93 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -46,7 +46,7 @@
public:
explicit RefreshRateHistory(nsecs_t minRefreshDuration)
: mMinRefreshDuration(minRefreshDuration) {}
- void insertRefreshRate(nsecs_t refreshRate) {
+ void insertRefreshRate(int refreshRate) {
mElements.push_back(refreshRate);
if (mElements.size() > HISTORY_SIZE) {
mElements.pop_front();
@@ -54,13 +54,13 @@
}
float getRefreshRateAvg() const {
- nsecs_t refreshDuration = mMinRefreshDuration;
- if (mElements.size() == HISTORY_SIZE) {
- refreshDuration = scheduler::calculate_mean(mElements);
+ if (mElements.empty()) {
+ return 1e9f / mMinRefreshDuration;
}
- return 1e9f / refreshDuration;
+ return scheduler::calculate_mean(mElements);
}
+
void clearHistory() { mElements.clear(); }
private:
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index afcf3d4..bb24f73 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -119,14 +119,15 @@
}
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
- const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
+ const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
+ ResyncCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const int64_t id = sNextId++;
ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
std::unique_ptr<EventThread> eventThread =
makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
- std::move(interceptCallback));
+ offsetThresholdForNextVsync, std::move(interceptCallback));
auto eventThreadConnection =
createConnectionInternal(eventThread.get(), std::move(resyncCallback),
@@ -139,10 +140,12 @@
}
std::unique_ptr<EventThread> Scheduler::makeEventThread(
- const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
+ nsecs_t offsetThresholdForNextVsync,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
std::unique_ptr<VSyncSource> eventThreadSource =
- std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
+ std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, offsetThresholdForNextVsync,
+ true, connectionName);
return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
std::move(interceptCallback), connectionName);
}
@@ -312,7 +315,7 @@
mPrimaryDispSync->setIgnorePresentFences(ignore);
}
-nsecs_t Scheduler::expectedPresentTime() {
+nsecs_t Scheduler::getDispSyncExpectedPresentTime() {
return mPrimaryDispSync->expectedPresentTime();
}
@@ -407,6 +410,10 @@
if (mSupportKernelTimer) {
resetIdleTimer();
}
+
+ // Touch event will boost the refresh rate to performance.
+ // Clear Layer History to get fresh FPS detection
+ mLayerHistory.clearHistory();
}
void Scheduler::resetTimerCallback() {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 597f9a2..eaad37c 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -96,8 +96,8 @@
virtual ~Scheduler();
/** Creates an EventThread connection. */
- sp<ConnectionHandle> createConnection(const char* connectionName, int64_t phaseOffsetNs,
- ResyncCallback,
+ sp<ConnectionHandle> createConnection(const char* connectionName, nsecs_t phaseOffsetNs,
+ nsecs_t offsetThresholdForNextVsync, ResyncCallback,
impl::EventThread::InterceptVSyncsCallback);
sp<IDisplayEventConnection> createDisplayEventConnection(
@@ -150,7 +150,7 @@
void addResyncSample(const nsecs_t timestamp, bool* periodFlushed);
void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
void setIgnorePresentFences(bool ignore);
- nsecs_t expectedPresentTime();
+ nsecs_t getDispSyncExpectedPresentTime();
// Registers the layer in the scheduler, and returns the handle for future references.
std::unique_ptr<scheduler::LayerHistory::LayerHandle> registerLayer(std::string const& name,
int windowType);
@@ -185,7 +185,8 @@
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
- const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
+ nsecs_t offsetThresholdForNextVsync,
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index 41c3a3a..73a1fb9 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -56,10 +56,12 @@
// appEarly: Like sfEarly, but for the app-vsync
// appEarlyGl: Like sfEarlyGl, but for the app-vsync.
// appLate: The regular app vsync phase offset.
- void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) {
+ void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
+ nsecs_t thresholdForNextVsync) {
mEarlyOffsets = early;
mEarlyGlOffsets = earlyGl;
mLateOffsets = late;
+ mThresholdForNextVsync = thresholdForNextVsync;
if (mSfConnectionHandle && late.sf != mOffsets.load().sf) {
mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf);
@@ -192,6 +194,7 @@
Offsets mLateOffsets;
Offsets mEarlyOffsets;
Offsets mEarlyGlOffsets;
+ nsecs_t mThresholdForNextVsync;
EventThread* mSfEventThread = nullptr;
EventThread* mAppEventThread = nullptr;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 31687ca..b7ee952 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -382,7 +382,8 @@
mLumaSampling = atoi(value);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
+ mVsyncModulator.setPhaseOffsets(early, gl, late,
+ mPhaseOffsets->getOffsetThresholdForNextVsync());
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
@@ -621,13 +622,16 @@
mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
mAppConnectionHandle =
- mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
+ mScheduler->createConnection("app", mVsyncModulator.getOffsets().app,
+ mPhaseOffsets->getOffsetThresholdForNextVsync(),
resyncCallback,
impl::EventThread::InterceptVSyncsCallback());
- mSfConnectionHandle = mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
- resyncCallback, [this](nsecs_t timestamp) {
- mInterceptor->saveVSyncEvent(timestamp);
- });
+ mSfConnectionHandle =
+ mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf,
+ mPhaseOffsets->getOffsetThresholdForNextVsync(),
+ resyncCallback, [this](nsecs_t timestamp) {
+ mInterceptor->saveVSyncEvent(timestamp);
+ });
mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
@@ -940,15 +944,13 @@
// Start receiving vsync samples now, so that we can detect a period
// switch.
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
- // We should only move to early offsets when we know that the refresh
- // rate will change. Otherwise, we may be stuck in early offsets
- // forever, as onRefreshRateChangeDetected will not be called.
- if (mDesiredActiveConfig.event == Scheduler::ConfigEvent::Changed) {
- mVsyncModulator.onRefreshRateChangeInitiated();
- }
+ // As we called to set period, we will call to onRefreshRateChangeCompleted once
+ // DispSync model is locked.
+ mVsyncModulator.onRefreshRateChangeInitiated();
mPhaseOffsets->setRefreshRateType(info.type);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
+ mVsyncModulator.setPhaseOffsets(early, gl, late,
+ mPhaseOffsets->getOffsetThresholdForNextVsync());
}
mDesiredActiveConfigChanged = true;
ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
@@ -980,10 +982,10 @@
display->setActiveConfig(mUpcomingActiveConfig.configId);
- mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
+ mVsyncModulator.setPhaseOffsets(early, gl, late,
+ mPhaseOffsets->getOffsetThresholdForNextVsync());
ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
@@ -992,6 +994,19 @@
}
}
+void SurfaceFlinger::desiredActiveConfigChangeDone() {
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
+ mDesiredActiveConfigChanged = false;
+ ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+
+ mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+ mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
+ const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+ mVsyncModulator.setPhaseOffsets(early, gl, late,
+ mPhaseOffsets->getOffsetThresholdForNextVsync());
+}
+
bool SurfaceFlinger::performSetActiveConfig() {
ATRACE_CALL();
if (mCheckPendingFence) {
@@ -1021,14 +1036,7 @@
if (!display || display->getActiveConfig() == desiredActiveConfig.configId) {
// display is not valid or we are already in the requested mode
// on both cases there is nothing left to do
- std::lock_guard<std::mutex> lock(mActiveConfigLock);
- mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
- mDesiredActiveConfigChanged = false;
- // Update scheduler with the correct vsync period as a no-op.
- // Otherwise, there exists a race condition where we get stuck in the
- // incorrect vsync period.
- mScheduler->resyncToHardwareVsync(false, getVsyncPeriod());
- ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+ desiredActiveConfigChangeDone();
return false;
}
@@ -1036,15 +1044,7 @@
// allowed configs might have change by the time we process the refresh.
// Make sure the desired config is still allowed
if (!isDisplayConfigAllowed(desiredActiveConfig.configId)) {
- std::lock_guard<std::mutex> lock(mActiveConfigLock);
- mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
- mDesiredActiveConfig.configId = display->getActiveConfig();
- mDesiredActiveConfigChanged = false;
- // Update scheduler with the current vsync period as a no-op.
- // Otherwise, there exists a race condition where we get stuck in the
- // incorrect vsync period.
- mScheduler->resyncToHardwareVsync(false, getVsyncPeriod());
- ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+ desiredActiveConfigChangeDone();
return false;
}
mUpcomingActiveConfig = desiredActiveConfig;
@@ -1543,10 +1543,23 @@
void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) {
ATRACE_CALL();
- Mutex::Autolock lock(mStateLock);
+
+ // Enable / Disable HWVsync from the main thread to avoid race conditions with
+ // display power state.
+ postMessageAsync(new LambdaMessage(
+ [=]() NO_THREAD_SAFETY_ANALYSIS { setPrimaryVsyncEnabledInternal(enabled); }));
+}
+
+void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) {
+ ATRACE_CALL();
+
+ mHWCVsyncPendingState = enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable;
+
if (const auto displayId = getInternalDisplayIdLocked()) {
- getHwComposer().setVsyncEnabled(*displayId,
- enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
+ sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
+ if (display && display->isPoweredOn()) {
+ setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
+ }
}
}
@@ -1656,6 +1669,18 @@
return fence != Fence::NO_FENCE && (fence->getStatus() == Fence::Status::Unsignaled);
}
+nsecs_t SurfaceFlinger::getExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS {
+ DisplayStatInfo stats;
+ mScheduler->getDisplayStatInfo(&stats);
+ const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime();
+ // Inflate the expected present time if we're targetting the next vsync.
+ const nsecs_t correctedTime =
+ mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
+ ? presentTime
+ : presentTime + stats.vsyncPeriod;
+ return correctedTime;
+}
+
void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
switch (what) {
@@ -3264,8 +3289,7 @@
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (layer->hasReadyFrame()) {
frameQueued = true;
- nsecs_t expectedPresentTime;
- expectedPresentTime = mScheduler->expectedPresentTime();
+ const nsecs_t expectedPresentTime = getExpectedPresentTime();
if (layer->shouldPresentNow(expectedPresentTime)) {
mLayersWithQueuedFrames.push_back(layer);
} else {
@@ -3662,7 +3686,7 @@
bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
const Vector<ComposerState>& states) {
- nsecs_t expectedPresentTime = mScheduler->expectedPresentTime();
+ nsecs_t expectedPresentTime = getExpectedPresentTime();
// Do not present if the desiredPresentTime has not passed unless it is more than one second
// in the future. We ignore timestamps more than 1 second in the future for stability reasons.
if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime &&
@@ -4428,6 +4452,13 @@
new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
}
+void SurfaceFlinger::setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled) {
+ if (mHWCVsyncState != enabled) {
+ getHwComposer().setVsyncEnabled(displayId, enabled);
+ mHWCVsyncState = enabled;
+ }
+}
+
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
if (display->isVirtual()) {
ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
@@ -4454,6 +4485,7 @@
// Turn on the display
getHwComposer().setPowerMode(*displayId, mode);
if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
+ setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
}
@@ -4479,6 +4511,9 @@
mScheduler->onScreenReleased(mAppConnectionHandle);
}
+ // Make sure HWVsync is disabled before turning off the display
+ setVsyncEnabledInHWC(*displayId, HWC2::Vsync::Disable);
+
getHwComposer().setPowerMode(*displayId, mode);
mVisibleRegionsDirty = true;
// from this point on, SF will stop drawing on this display
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 40941f2..a8057aa 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -293,11 +293,19 @@
// TODO: this should be made accessible only to EventThread
void setPrimaryVsyncEnabled(bool enabled);
+ // main thread function to enable/disable h/w composer event
+ void setPrimaryVsyncEnabledInternal(bool enabled);
+
// called on the main thread by MessageQueue when an internal message
// is received
// TODO: this should be made accessible only to MessageQueue
void onMessageReceived(int32_t what);
+ // Returns the expected present time for this frame.
+ // When we are in negative offsets, we perform a correction so that the
+ // predicted vsync for the *next* frame is used instead.
+ nsecs_t getExpectedPresentTime();
+
// for debugging only
// TODO: this should be made accessible only to HWComposer
const Vector<sp<Layer>>& getLayerSortedByZForHwcDisplay(DisplayId displayId);
@@ -510,13 +518,15 @@
// Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock);
// Once HWC has returned the present fence, this sets the active config and a new refresh
- // rate in SF. It also triggers HWC vsync.
+ // rate in SF.
void setActiveConfigInternal() REQUIRES(mStateLock);
// Active config is updated on INVALIDATE call in a state machine-like manner. When the
// desired config was set, HWC needs to update the panel on the next refresh, and when
// we receive the fence back, we know that the process was complete. It returns whether
// we need to wait for the next invalidate
bool performSetActiveConfig() REQUIRES(mStateLock);
+ // Called when active config is no longer is progress
+ void desiredActiveConfigChangeDone() REQUIRES(mStateLock);
// called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
@@ -835,6 +845,7 @@
}
bool previousFrameMissed();
+ void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled);
/*
* Debugging & dumpsys
@@ -1169,6 +1180,10 @@
// The Layer pointer is removed from the set when the destructor is called so there shouldn't
// be any issues with a raw pointer referencing an invalid object.
std::unordered_set<Layer*> mOffscreenLayers;
+
+ // Flags to capture the state of Vsync in HWC
+ HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable;
+ HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable;
};
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index 2e705da..0aa8cf5 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -51,6 +51,7 @@
AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder;
static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms;
+ static constexpr std::chrono::nanoseconds mOffsetThresholdForNextVsync = 16ms;
static constexpr int mIterations = 100;
};
@@ -78,7 +79,8 @@
void DispSyncSourceTest::createDispSyncSource() {
createDispSync();
- mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true,
+ mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(),
+ mOffsetThresholdForNextVsync.count(), true,
"DispSyncSourceTest");
mDispSyncSource->setCallback(this);
}
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index af5ccbc..740115e 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -48,7 +48,7 @@
std::unique_ptr<EventThread> makeEventThread(
const char* /* connectionName */, DispSync* /* dispSync */,
- nsecs_t /* phaseOffsetNs */,
+ nsecs_t /* phaseOffsetNs */, nsecs_t /* offsetThresholdForNextVsync */,
impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
return std::move(mEventThread);
}
@@ -85,7 +85,7 @@
EXPECT_CALL(*mEventThread, createEventConnection(_, _))
.WillRepeatedly(Return(mEventThreadConnection));
- mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(),
+ mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, ResyncCallback(),
impl::EventThread::InterceptVSyncsCallback());
EXPECT_TRUE(mConnectionHandle != nullptr);
}