diff options
| -rw-r--r-- | services/surfaceflinger/BufferQueueLayer.cpp | 2 | ||||
| -rw-r--r-- | services/surfaceflinger/Scheduler/PhaseOffsets.cpp | 6 | ||||
| -rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.cpp | 6 | ||||
| -rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.h | 4 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 163 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 49 |
6 files changed, 182 insertions, 48 deletions
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 39157575e9..0313c326a5 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -232,7 +232,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t getTransformToDisplayInverse(), mFreezeGeometryUpdates); const nsecs_t expectedPresentTime = mFlinger->mUseScheduler - ? mFlinger->mScheduler->mPrimaryDispSync->expectedPresentTime() + ? mFlinger->mScheduler->expectedPresentTime() : mFlinger->mPrimaryDispSync->expectedPresentTime(); // updateTexImage() below might drop the some buffers at the head of the queue if there is a diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index a0a4455d43..ab1f460357 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -59,10 +59,10 @@ PhaseOffsets::PhaseOffsets() { const int highFpsEarlyGlAppOffsetNs = atoi(value); // TODO(b/122905996): Define these in device.mk. - property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "1000000"); + property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "2000000"); const int highFpsLateAppOffsetNs = atoi(value); - property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "8000000"); + property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "1000000"); const int highFpsLateSfOffsetNs = atoi(value); mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs @@ -83,7 +83,7 @@ PhaseOffsets::PhaseOffsets() { : highFpsLateAppOffsetNs, highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs : highFpsLateSfOffsetNs}; - mHighRefreshRateOffsets.late = {highFpsLateAppOffsetNs, highFpsLateSfOffsetNs}; + mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}; } PhaseOffsets::Offsets PhaseOffsets::getCurrentOffsets() const { diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 2f581d2fcb..5268c8cc7b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -69,7 +69,7 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function) mEventControlThread = std::make_unique<impl::EventControlThread>(function); char value[PROPERTY_VALUE_MAX]; - property_get("debug.sf.set_idle_timer_ms", value, "30"); + property_get("debug.sf.set_idle_timer_ms", value, "0"); mSetIdleTimerMs = atoi(value); if (mSetIdleTimerMs > 0) { @@ -238,6 +238,10 @@ void Scheduler::makeHWSyncAvailable(bool makeAvailable) { mHWVsyncAvailable = makeAvailable; } +nsecs_t Scheduler::expectedPresentTime() { + return mPrimaryDispSync->expectedPresentTime(); +} + void Scheduler::addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp, const std::string layerName) { // This is V1 logic. It calculates the average FPS based on the timestamp frequency diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 4abf027c14..089d579b03 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -109,6 +109,7 @@ public: void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime); void setIgnorePresentFences(bool ignore); void makeHWSyncAvailable(bool makeAvailable); + nsecs_t expectedPresentTime(); // Adds the present time for given layer to the history of present times. void addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp, const std::string layerName); @@ -142,9 +143,6 @@ private: // Function that is called when the timer expires. void expiredTimerCallback(); - // TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it - // should make request to Scheduler to compute next refresh. - friend class BufferQueueLayer; // If fences from sync Framework are supported. const bool mHasSyncFramework; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5f8de830e5..6e21739e53 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -351,10 +351,6 @@ SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory) } ALOGV("Primary Display Orientation is set to %2d.", SurfaceFlinger::primaryDisplayOrientation); - mPrimaryDispSync = - getFactory().createDispSync("PrimaryDispSync", SurfaceFlinger::hasSyncFramework, - SurfaceFlinger::dispSyncPresentTimeOffset); - auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService(); if (surfaceFlingerConfigsServiceV1_2) { surfaceFlingerConfigsServiceV1_2->getDisplayNativePrimaries( @@ -400,6 +396,12 @@ SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory) property_get("debug.sf.use_scheduler", value, "0"); mUseScheduler = atoi(value); + if (!mUseScheduler) { + mPrimaryDispSync = + getFactory().createDispSync("PrimaryDispSync", SurfaceFlinger::hasSyncFramework, + SurfaceFlinger::dispSyncPresentTimeOffset); + } + const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); mVsyncModulator.setPhaseOffsets(early, gl, late); @@ -719,8 +721,10 @@ void SurfaceFlinger::init() { } } - mEventControlThread = getFactory().createEventControlThread( - [this](bool enabled) { setPrimaryVsyncEnabled(enabled); }); + if (!mUseScheduler) { + mEventControlThread = getFactory().createEventControlThread( + [this](bool enabled) { setPrimaryVsyncEnabled(enabled); }); + } // initialize our drawing state mDrawingState = mCurrentState; @@ -822,14 +826,12 @@ status_t SurfaceFlinger::getSupportedFrameTimestamps( return NO_ERROR; } -status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken, - Vector<DisplayInfo>* configs) { +status_t SurfaceFlinger::getDisplayConfigsLocked(const sp<IBinder>& displayToken, + Vector<DisplayInfo>* configs) { if (!displayToken || !configs) { return BAD_VALUE; } - ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); - const auto displayId = getPhysicalDisplayIdLocked(displayToken); if (!displayId) { return NAME_NOT_FOUND; @@ -957,22 +959,19 @@ int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) { return display->getActiveConfig(); } -status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) { - ATRACE_NAME("setActiveConfigSync"); - postMessageSync(new LambdaMessage( - [&]() NO_THREAD_SAFETY_ANALYSIS { setActiveConfigInternal(displayToken, mode); })); - return NO_ERROR; -} +void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode) { + ATRACE_CALL(); -void SurfaceFlinger::setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) { Vector<DisplayInfo> configs; - getDisplayConfigs(displayToken, &configs); + // Lock is acquired by setRefreshRateTo. + getDisplayConfigsLocked(displayToken, &configs); if (mode < 0 || mode >= static_cast<int>(configs.size())) { ALOGE("Attempt to set active config %d for display with %zu configs", mode, configs.size()); return; } - const auto display = getDisplayDevice(displayToken); + // Lock is acquired by setRefreshRateTo. + const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set active config %d for invalid display token %p", mode, displayToken.get()); @@ -988,23 +987,95 @@ void SurfaceFlinger::setActiveConfigInternal(const sp<IBinder>& displayToken, in return; } - int currentMode = display->getActiveConfig(); - if (mode == currentMode) { - // Don't update config if we are already running in the desired mode. + // Don't check against the current mode yet. Worst case we set the desired + // config twice. + { + std::lock_guard<std::mutex> lock(mActiveConfigLock); + mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken}; + } + // This will trigger HWC refresh without resetting the idle timer. + repaintEverythingForHWC(); +} + +status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) { + ATRACE_CALL(); + postMessageSync(new LambdaMessage( + [&]() NO_THREAD_SAFETY_ANALYSIS { setDesiredActiveConfig(displayToken, mode); })); + return NO_ERROR; +} + +void SurfaceFlinger::setActiveConfigInHWC() { + ATRACE_CALL(); + + const auto display = getDisplayDevice(mUpcomingActiveConfig.displayToken); + if (!display) { return; } + const auto displayId = display->getId(); + LOG_ALWAYS_FATAL_IF(!displayId); + + ATRACE_INT("ActiveConfigModeHWC", mUpcomingActiveConfig.configId); + getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId); + mSetActiveConfigState = SetActiveConfigState::NOTIFIED_HWC; + ATRACE_INT("SetActiveConfigState", mSetActiveConfigState); +} + +void SurfaceFlinger::setActiveConfigInternal() { + ATRACE_CALL(); + + std::lock_guard<std::mutex> lock(mActiveConfigLock); if (mUseScheduler) { - mRefreshRateStats->setConfigMode(mode); + mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId); } - const auto displayId = display->getId(); - LOG_ALWAYS_FATAL_IF(!displayId); + const auto display = getDisplayDeviceLocked(mUpcomingActiveConfig.displayToken); + display->setActiveConfig(mUpcomingActiveConfig.configId); - display->setActiveConfig(mode); - getHwComposer().setActiveConfig(*displayId, mode); + mSetActiveConfigState = SetActiveConfigState::NONE; + ATRACE_INT("SetActiveConfigState", mSetActiveConfigState); - ATRACE_INT("ActiveConfigMode", mode); resyncToHardwareVsync(true, getVsyncPeriod()); + ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId); +} + +bool SurfaceFlinger::updateSetActiveConfigStateMachine() NO_THREAD_SAFETY_ANALYSIS { + // Store the local variable to release the lock. + ActiveConfigInfo desiredActiveConfig; + { + std::lock_guard<std::mutex> lock(mActiveConfigLock); + desiredActiveConfig = mDesiredActiveConfig; + } + + const auto display = getDisplayDevice(desiredActiveConfig.displayToken); + if (display) { + if (mSetActiveConfigState == SetActiveConfigState::NONE && + display->getActiveConfig() != desiredActiveConfig.configId) { + // Step 1) Desired active config was set, it is different than the + // config currently in use. Notify HWC. + mUpcomingActiveConfig = desiredActiveConfig; + setActiveConfigInHWC(); + } else if (mSetActiveConfigState == SetActiveConfigState::NOTIFIED_HWC) { + // Step 2) HWC was notified and we received refresh from it. + mSetActiveConfigState = SetActiveConfigState::REFRESH_RECEIVED; + ATRACE_INT("SetActiveConfigState", mSetActiveConfigState); + repaintEverythingForHWC(); + // We do not want to give another frame to HWC while we are transitioning. + return false; + } else if (mSetActiveConfigState == SetActiveConfigState::REFRESH_RECEIVED && + !(mPreviousPresentFence != Fence::NO_FENCE && + (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled))) { + // Step 3) We received the present fence from the HWC, so we assume it + // successfully updated the config, hence we update SF. + setActiveConfigInternal(); + // If the config changed again while we were transitioning, restart the + // process. + if (desiredActiveConfig != mUpcomingActiveConfig) { + mUpcomingActiveConfig = desiredActiveConfig; + setActiveConfigInHWC(); // sets the state to NOTIFY_HWC + } + } + } + return true; } status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken, @@ -1332,6 +1403,7 @@ nsecs_t SurfaceFlinger::getVsyncPeriod() const { } void SurfaceFlinger::enableHardwareVsync() { + assert(!mUseScheduler); Mutex::Autolock _l(mHWVsyncLock); if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { mPrimaryDispSync->beginResync(); @@ -1374,6 +1446,7 @@ void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) { } void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) { + assert(!mUseScheduler); Mutex::Autolock _l(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { mEventControlThread->setVsyncEnabled(false); @@ -1482,8 +1555,7 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate) { // TODO(b/113612090): There should be a better way at determining which config // has the right refresh rate. if (std::abs(fps - newFps) <= 1) { - setActiveConfigInternal(getInternalDisplayTokenLocked(), i); - ATRACE_INT("FPS", newFps); + setDesiredActiveConfig(getInternalDisplayTokenLocked(), i); } } } @@ -1627,14 +1699,16 @@ void SurfaceFlinger::onMessageReceived(int32_t what) { ATRACE_CALL(); switch (what) { case MessageQueue::INVALIDATE: { + if (!updateSetActiveConfigStateMachine()) { + break; + } + if (mUseScheduler) { // This call is made each time SF wakes up and creates a new frame. mScheduler->incrementFrameCounter(); } - bool frameMissed = !mHadClientComposition && - mPreviousPresentFence != Fence::NO_FENCE && - (mPreviousPresentFence->getSignalTime() == - Fence::SIGNAL_TIME_PENDING); + bool frameMissed = !mHadClientComposition && mPreviousPresentFence != Fence::NO_FENCE && + (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled); mFrameMissedCount += frameMissed; ATRACE_INT("FrameMissed", static_cast<int>(frameMissed)); if (frameMissed) { @@ -3041,7 +3115,12 @@ void SurfaceFlinger::updateCursorAsync() void SurfaceFlinger::latchAndReleaseBuffer(const sp<Layer>& layer) { if (layer->hasReadyFrame()) { - const nsecs_t expectedPresentTime = mPrimaryDispSync->expectedPresentTime(); + nsecs_t expectedPresentTime; + if (mUseScheduler) { + expectedPresentTime = mScheduler->expectedPresentTime(); + } else { + expectedPresentTime = mPrimaryDispSync->expectedPresentTime(); + } if (layer->shouldPresentNow(expectedPresentTime)) { bool ignored = false; layer->latchBuffer(ignored, systemTime(), Fence::NO_FENCE); @@ -3273,7 +3352,12 @@ bool SurfaceFlinger::handlePageFlip() mDrawingState.traverseInZOrder([&](Layer* layer) { if (layer->hasReadyFrame()) { frameQueued = true; - const nsecs_t expectedPresentTime = mPrimaryDispSync->expectedPresentTime(); + nsecs_t expectedPresentTime; + if (mUseScheduler) { + expectedPresentTime = mScheduler->expectedPresentTime(); + } else { + expectedPresentTime = mPrimaryDispSync->expectedPresentTime(); + } if (layer->shouldPresentNow(expectedPresentTime)) { mLayersWithQueuedFrames.push_back(layer); } else { @@ -3614,7 +3698,12 @@ bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>& bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, const Vector<ComposerState>& states) { - const nsecs_t expectedPresentTime = mPrimaryDispSync->expectedPresentTime(); + nsecs_t expectedPresentTime; + if (mUseScheduler) { + expectedPresentTime = mScheduler->expectedPresentTime(); + } else { + expectedPresentTime = mPrimaryDispSync->expectedPresentTime(); + } // 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 && diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6546973411..a748bc599e 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -437,7 +437,12 @@ private: const Rect& sourceCrop, float frameScale, bool childrenOnly) override; status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override; status_t getDisplayConfigs(const sp<IBinder>& displayToken, - Vector<DisplayInfo>* configs) override; + Vector<DisplayInfo>* configs) override { + Mutex::Autolock _l(mStateLock); + return getDisplayConfigsLocked(displayToken, configs); + } + status_t getDisplayConfigsLocked(const sp<IBinder>& displayToken, Vector<DisplayInfo>* configs) + REQUIRES(mStateLock); int getActiveConfig(const sp<IBinder>& displayToken) override; status_t getDisplayColorModes(const sp<IBinder>& displayToken, Vector<ui::ColorMode>* configs) override; @@ -503,8 +508,18 @@ private: // called on the main thread in response to initializeDisplays() void onInitializeDisplays() REQUIRES(mStateLock); - // called on the main thread in response to setActiveConfig() - void setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) REQUIRES(mStateLock); + // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig. + void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode) REQUIRES(mStateLock); + // Calls setActiveConfig in HWC. + void setActiveConfigInHWC(); + // Once HWC has returned the present fence, this sets the active config and a new refresh + // rate in SF. It also triggers HWC vsync. + 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 pannel on the next refresh, and when + // we receive the fence back, we know that the process was complete. It returns whether + // the invalidate process should continue. + bool updateSetActiveConfigStateMachine(); // called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock); @@ -1084,6 +1099,34 @@ private: sp<Scheduler::ConnectionHandle> mSfConnectionHandle; std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats; + // The following structs are used for configuring active config state at a desired time, + // which is once per vsync at invalidate time. + enum SetActiveConfigState { + NONE, // not in progress + NOTIFIED_HWC, // call to HWC has been made + REFRESH_RECEIVED // onRefresh was received from HWC + }; + std::atomic<SetActiveConfigState> mSetActiveConfigState = SetActiveConfigState::NONE; + + struct ActiveConfigInfo { + int configId; + sp<IBinder> displayToken; + + bool operator!=(const ActiveConfigInfo& other) const { + if (configId != other.configId) { + return true; + } + return (displayToken != other.displayToken); + } + }; + std::mutex mActiveConfigLock; + // This bit is set once we start setting the config. We read from this bit during the + // process. If at the end, this bit is different than mDesiredActiveConfig, we restart + // the process. + ActiveConfigInfo mUpcomingActiveConfig; // Always read and written on the main thread. + // This bit can be set at any point in time when the system wants the new config. + ActiveConfigInfo mDesiredActiveConfig GUARDED_BY(mActiveConfigLock); + /* ------------------------------------------------------------------------ */ sp<IInputFlinger> mInputFlinger; |