Loading services/surfaceflinger/RegionSamplingThread.cpp +180 −5 Original line number Diff line number Diff line Loading @@ -21,27 +21,168 @@ #include "RegionSamplingThread.h" #include <cutils/properties.h> #include <gui/IRegionSamplingListener.h> #include <utils/Trace.h> #include <string> #include "DisplayDevice.h" #include "Layer.h" #include "SurfaceFlinger.h" namespace android { using namespace std::chrono_literals; template <typename T> struct SpHash { size_t operator()(const sp<T>& p) const { return std::hash<T*>()(p.get()); } }; RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger) : mFlinger(flinger) { constexpr auto lumaSamplingStepTag = "LumaSamplingStep"; enum class samplingStep { noWorkNeeded, idleTimerWaiting, waitForZeroPhase, waitForSamplePhase, sample }; constexpr auto defaultRegionSamplingOffset = -3ms; constexpr auto defaultRegionSamplingPeriod = 100ms; constexpr auto defaultRegionSamplingTimerTimeout = 100ms; // TODO: (b/127403193) duration to string conversion could probably be constexpr template <typename Rep, typename Per> inline std::string toNsString(std::chrono::duration<Rep, Per> t) { return std::to_string(std::chrono::duration_cast<std::chrono::nanoseconds>(t).count()); } RegionSamplingThread::EnvironmentTimingTunables::EnvironmentTimingTunables() { char value[PROPERTY_VALUE_MAX] = {}; property_get("debug.sf.region_sampling_offset_ns", value, toNsString(defaultRegionSamplingOffset).c_str()); int const samplingOffsetNsRaw = atoi(value); property_get("debug.sf.region_sampling_period_ns", value, toNsString(defaultRegionSamplingPeriod).c_str()); int const samplingPeriodNsRaw = atoi(value); property_get("debug.sf.region_sampling_timer_timeout_ns", value, toNsString(defaultRegionSamplingTimerTimeout).c_str()); int const samplingTimerTimeoutNsRaw = atoi(value); if ((samplingPeriodNsRaw < 0) || (samplingTimerTimeoutNsRaw < 0)) { ALOGW("User-specified sampling tuning options nonsensical. Using defaults"); mSamplingOffset = defaultRegionSamplingOffset; mSamplingPeriod = defaultRegionSamplingPeriod; mSamplingTimerTimeout = defaultRegionSamplingTimerTimeout; } else { mSamplingOffset = std::chrono::nanoseconds(samplingOffsetNsRaw); mSamplingPeriod = std::chrono::nanoseconds(samplingPeriodNsRaw); mSamplingTimerTimeout = std::chrono::nanoseconds(samplingTimerTimeoutNsRaw); } } struct SamplingOffsetCallback : DispSync::Callback { SamplingOffsetCallback(RegionSamplingThread& samplingThread, Scheduler& scheduler, std::chrono::nanoseconds targetSamplingOffset) : mRegionSamplingThread(samplingThread), mScheduler(scheduler), mTargetSamplingOffset(targetSamplingOffset) {} ~SamplingOffsetCallback() { stopVsyncListener(); } SamplingOffsetCallback(const SamplingOffsetCallback&) = delete; SamplingOffsetCallback& operator=(const SamplingOffsetCallback&) = delete; void startVsyncListener() { std::lock_guard lock(mMutex); if (mVsyncListening) return; mPhaseIntervalSetting = Phase::ZERO; mScheduler.withPrimaryDispSync([this](android::DispSync& sync) { sync.addEventListener("SamplingThreadDispSyncListener", 0, this); }); mVsyncListening = true; } void stopVsyncListener() { std::lock_guard lock(mMutex); stopVsyncListenerLocked(); } private: void stopVsyncListenerLocked() /*REQUIRES(mMutex)*/ { if (!mVsyncListening) return; mScheduler.withPrimaryDispSync( [this](android::DispSync& sync) { sync.removeEventListener(this); }); mVsyncListening = false; } void onDispSyncEvent(nsecs_t /* when */) final { std::unique_lock<decltype(mMutex)> lock(mMutex); if (mPhaseIntervalSetting == Phase::ZERO) { ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForSamplePhase)); mPhaseIntervalSetting = Phase::SAMPLING; mScheduler.withPrimaryDispSync([this](android::DispSync& sync) { sync.changePhaseOffset(this, mTargetSamplingOffset.count()); }); return; } if (mPhaseIntervalSetting == Phase::SAMPLING) { mPhaseIntervalSetting = Phase::ZERO; mScheduler.withPrimaryDispSync( [this](android::DispSync& sync) { sync.changePhaseOffset(this, 0); }); stopVsyncListenerLocked(); lock.unlock(); mRegionSamplingThread.notifySamplingOffset(); return; } } RegionSamplingThread& mRegionSamplingThread; Scheduler& mScheduler; const std::chrono::nanoseconds mTargetSamplingOffset; mutable std::mutex mMutex; enum class Phase { ZERO, SAMPLING } mPhaseIntervalSetting /*GUARDED_BY(mMutex) macro doesnt work with unique_lock?*/ = Phase::ZERO; bool mVsyncListening /*GUARDED_BY(mMutex)*/ = false; }; RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler, const TimingTunables& tunables) : mFlinger(flinger), mScheduler(scheduler), mTunables(tunables), mIdleTimer(std::chrono::duration_cast<std::chrono::milliseconds>( mTunables.mSamplingTimerTimeout), [] {}, [this] { checkForStaleLuma(); }), mPhaseCallback(std::make_unique<SamplingOffsetCallback>(*this, mScheduler, tunables.mSamplingOffset)), lastSampleTime(0ns) { { std::lock_guard threadLock(mThreadMutex); mThread = std::thread([this]() { threadMain(); }); pthread_setname_np(mThread.native_handle(), "RegionSamplingThread"); } mIdleTimer.start(); } RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler) : RegionSamplingThread(flinger, scheduler, TimingTunables{defaultRegionSamplingOffset, defaultRegionSamplingPeriod, defaultRegionSamplingTimerTimeout}) {} RegionSamplingThread::~RegionSamplingThread() { mIdleTimer.stop(); { std::lock_guard lock(mMutex); mRunning = false; Loading Loading @@ -71,8 +212,41 @@ void RegionSamplingThread::removeListener(const sp<IRegionSamplingListener>& lis mDescriptors.erase(wp<IBinder>(IInterface::asBinder(listener))); } void RegionSamplingThread::sampleNow() { void RegionSamplingThread::checkForStaleLuma() { std::lock_guard lock(mMutex); if (mDiscardedFrames) { ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForZeroPhase)); mDiscardedFrames = false; mPhaseCallback->startVsyncListener(); } } void RegionSamplingThread::notifyNewContent() { doSample(); } void RegionSamplingThread::notifySamplingOffset() { doSample(); } void RegionSamplingThread::doSample() { std::lock_guard lock(mMutex); auto now = std::chrono::nanoseconds(systemTime(SYSTEM_TIME_MONOTONIC)); if (lastSampleTime + mTunables.mSamplingPeriod > now) { ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::idleTimerWaiting)); mDiscardedFrames = true; return; } ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::sample)); mDiscardedFrames = false; lastSampleTime = now; mIdleTimer.reset(); mPhaseCallback->stopVsyncListener(); mSampleRequested = true; mCondition.notify_one(); } Loading Loading @@ -238,6 +412,7 @@ void RegionSamplingThread::captureSample() { for (size_t d = 0; d < activeDescriptors.size(); ++d) { activeDescriptors[d].listener->onSampleCollected(lumas[d]); } ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::noWorkNeeded)); } void RegionSamplingThread::threadMain() { Loading services/surfaceflinger/RegionSamplingThread.h +43 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include <chrono> #include <condition_variable> #include <mutex> #include <thread> Loading @@ -25,17 +26,42 @@ #include <binder/IBinder.h> #include <ui/Rect.h> #include <utils/StrongPointer.h> #include "Scheduler/IdleTimer.h" namespace android { class GraphicBuffer; class IRegionSamplingListener; class Layer; class Scheduler; class SurfaceFlinger; struct SamplingOffsetCallback; class RegionSamplingThread : public IBinder::DeathRecipient { public: explicit RegionSamplingThread(SurfaceFlinger& flinger); struct TimingTunables { // debug.sf.sampling_offset_ns // When asynchronously collecting sample, the offset, from zero phase in the vsync timeline // at which the sampling should start. std::chrono::nanoseconds mSamplingOffset; // debug.sf.sampling_period_ns // This is the maximum amount of time the luma recieving client // should have to wait for a new luma value after a frame is updated. The inverse of this is // roughly the sampling rate. Sampling system rounds up sub-vsync sampling period to vsync // period. std::chrono::nanoseconds mSamplingPeriod; // debug.sf.sampling_timer_timeout_ns // This is the interval at which the luma sampling system will check that the luma clients // have up to date information. It defaults to the mSamplingPeriod. std::chrono::nanoseconds mSamplingTimerTimeout; }; struct EnvironmentTimingTunables : TimingTunables { EnvironmentTimingTunables(); }; explicit RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler, const TimingTunables& tunables); explicit RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler); ~RegionSamplingThread(); // Add a listener to receive luma notifications. The luma reported via listener will Loading @@ -44,8 +70,13 @@ public: const sp<IRegionSamplingListener>& listener); // Remove the listener to stop receiving median luma notifications. void removeListener(const sp<IRegionSamplingListener>& listener); // Instruct the thread to perform a median luma sampling on the layers. void sampleNow(); // Notifies sampling engine that new content is available. This will trigger a sampling // pass at some point in the future. void notifyNewContent(); // Notifies the sampling engine that it has a good timing window in which to sample. void notifySamplingOffset(); private: struct Descriptor { Loading @@ -63,12 +94,19 @@ private: const sp<GraphicBuffer>& buffer, const Point& leftTop, const std::vector<RegionSamplingThread::Descriptor>& descriptors); void doSample(); void binderDied(const wp<IBinder>& who) override; void checkForStaleLuma(); void captureSample() REQUIRES(mMutex); void threadMain(); SurfaceFlinger& mFlinger; Scheduler& mScheduler; const TimingTunables mTunables; scheduler::IdleTimer mIdleTimer; std::unique_ptr<SamplingOffsetCallback> const mPhaseCallback; std::mutex mThreadMutex; std::thread mThread GUARDED_BY(mThreadMutex); Loading @@ -79,6 +117,8 @@ private: bool mSampleRequested GUARDED_BY(mMutex) = false; std::unordered_map<wp<IBinder>, Descriptor, WpHash> mDescriptors GUARDED_BY(mMutex); std::chrono::nanoseconds lastSampleTime GUARDED_BY(mMutex); bool mDiscardedFrames GUARDED_BY(mMutex) = false; }; } // namespace android services/surfaceflinger/Scheduler/Scheduler.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -304,6 +304,10 @@ void Scheduler::addNativeWindowApi(int apiId) { mApiHistoryCounter = mApiHistoryCounter % scheduler::ARRAY_SIZE; } void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) { fn(*mPrimaryDispSync); } void Scheduler::updateFpsBasedOnNativeWindowApi() { int mode; { Loading services/surfaceflinger/Scheduler/Scheduler.h +4 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #pragma once #include <cstdint> #include <functional> #include <memory> #include <ui/DisplayStatInfo.h> Loading Loading @@ -104,6 +105,9 @@ public: // Getter methods. EventThread* getEventThread(const sp<ConnectionHandle>& handle); // Provides access to the DispSync object for the primary display. void withPrimaryDispSync(std::function<void(DispSync&)> const& fn); sp<EventThreadConnection> getEventConnection(const sp<ConnectionHandle>& handle); // Should be called when receiving a hotplug event. Loading services/surfaceflinger/SurfaceFlinger.cpp +6 −2 Original line number Diff line number Diff line Loading @@ -637,6 +637,10 @@ void SurfaceFlinger::init() { mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(), mSfConnectionHandle.get()); mRegionSamplingThread = new RegionSamplingThread(*this, *mScheduler, RegionSamplingThread::EnvironmentTimingTunables()); // Get a RenderEngine for the given display / config (can't fail) int32_t renderEngineFeature = 0; renderEngineFeature |= (useColorManagement ? Loading Loading @@ -2063,8 +2067,8 @@ void SurfaceFlinger::postComposition() mTransactionCompletedThread.addPresentFence(mPreviousPresentFence); mTransactionCompletedThread.sendCallbacks(); if (mLumaSampling) { mRegionSamplingThread->sampleNow(); if (mLumaSampling && mRegionSamplingThread) { mRegionSamplingThread->notifyNewContent(); } } Loading Loading
services/surfaceflinger/RegionSamplingThread.cpp +180 −5 Original line number Diff line number Diff line Loading @@ -21,27 +21,168 @@ #include "RegionSamplingThread.h" #include <cutils/properties.h> #include <gui/IRegionSamplingListener.h> #include <utils/Trace.h> #include <string> #include "DisplayDevice.h" #include "Layer.h" #include "SurfaceFlinger.h" namespace android { using namespace std::chrono_literals; template <typename T> struct SpHash { size_t operator()(const sp<T>& p) const { return std::hash<T*>()(p.get()); } }; RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger) : mFlinger(flinger) { constexpr auto lumaSamplingStepTag = "LumaSamplingStep"; enum class samplingStep { noWorkNeeded, idleTimerWaiting, waitForZeroPhase, waitForSamplePhase, sample }; constexpr auto defaultRegionSamplingOffset = -3ms; constexpr auto defaultRegionSamplingPeriod = 100ms; constexpr auto defaultRegionSamplingTimerTimeout = 100ms; // TODO: (b/127403193) duration to string conversion could probably be constexpr template <typename Rep, typename Per> inline std::string toNsString(std::chrono::duration<Rep, Per> t) { return std::to_string(std::chrono::duration_cast<std::chrono::nanoseconds>(t).count()); } RegionSamplingThread::EnvironmentTimingTunables::EnvironmentTimingTunables() { char value[PROPERTY_VALUE_MAX] = {}; property_get("debug.sf.region_sampling_offset_ns", value, toNsString(defaultRegionSamplingOffset).c_str()); int const samplingOffsetNsRaw = atoi(value); property_get("debug.sf.region_sampling_period_ns", value, toNsString(defaultRegionSamplingPeriod).c_str()); int const samplingPeriodNsRaw = atoi(value); property_get("debug.sf.region_sampling_timer_timeout_ns", value, toNsString(defaultRegionSamplingTimerTimeout).c_str()); int const samplingTimerTimeoutNsRaw = atoi(value); if ((samplingPeriodNsRaw < 0) || (samplingTimerTimeoutNsRaw < 0)) { ALOGW("User-specified sampling tuning options nonsensical. Using defaults"); mSamplingOffset = defaultRegionSamplingOffset; mSamplingPeriod = defaultRegionSamplingPeriod; mSamplingTimerTimeout = defaultRegionSamplingTimerTimeout; } else { mSamplingOffset = std::chrono::nanoseconds(samplingOffsetNsRaw); mSamplingPeriod = std::chrono::nanoseconds(samplingPeriodNsRaw); mSamplingTimerTimeout = std::chrono::nanoseconds(samplingTimerTimeoutNsRaw); } } struct SamplingOffsetCallback : DispSync::Callback { SamplingOffsetCallback(RegionSamplingThread& samplingThread, Scheduler& scheduler, std::chrono::nanoseconds targetSamplingOffset) : mRegionSamplingThread(samplingThread), mScheduler(scheduler), mTargetSamplingOffset(targetSamplingOffset) {} ~SamplingOffsetCallback() { stopVsyncListener(); } SamplingOffsetCallback(const SamplingOffsetCallback&) = delete; SamplingOffsetCallback& operator=(const SamplingOffsetCallback&) = delete; void startVsyncListener() { std::lock_guard lock(mMutex); if (mVsyncListening) return; mPhaseIntervalSetting = Phase::ZERO; mScheduler.withPrimaryDispSync([this](android::DispSync& sync) { sync.addEventListener("SamplingThreadDispSyncListener", 0, this); }); mVsyncListening = true; } void stopVsyncListener() { std::lock_guard lock(mMutex); stopVsyncListenerLocked(); } private: void stopVsyncListenerLocked() /*REQUIRES(mMutex)*/ { if (!mVsyncListening) return; mScheduler.withPrimaryDispSync( [this](android::DispSync& sync) { sync.removeEventListener(this); }); mVsyncListening = false; } void onDispSyncEvent(nsecs_t /* when */) final { std::unique_lock<decltype(mMutex)> lock(mMutex); if (mPhaseIntervalSetting == Phase::ZERO) { ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForSamplePhase)); mPhaseIntervalSetting = Phase::SAMPLING; mScheduler.withPrimaryDispSync([this](android::DispSync& sync) { sync.changePhaseOffset(this, mTargetSamplingOffset.count()); }); return; } if (mPhaseIntervalSetting == Phase::SAMPLING) { mPhaseIntervalSetting = Phase::ZERO; mScheduler.withPrimaryDispSync( [this](android::DispSync& sync) { sync.changePhaseOffset(this, 0); }); stopVsyncListenerLocked(); lock.unlock(); mRegionSamplingThread.notifySamplingOffset(); return; } } RegionSamplingThread& mRegionSamplingThread; Scheduler& mScheduler; const std::chrono::nanoseconds mTargetSamplingOffset; mutable std::mutex mMutex; enum class Phase { ZERO, SAMPLING } mPhaseIntervalSetting /*GUARDED_BY(mMutex) macro doesnt work with unique_lock?*/ = Phase::ZERO; bool mVsyncListening /*GUARDED_BY(mMutex)*/ = false; }; RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler, const TimingTunables& tunables) : mFlinger(flinger), mScheduler(scheduler), mTunables(tunables), mIdleTimer(std::chrono::duration_cast<std::chrono::milliseconds>( mTunables.mSamplingTimerTimeout), [] {}, [this] { checkForStaleLuma(); }), mPhaseCallback(std::make_unique<SamplingOffsetCallback>(*this, mScheduler, tunables.mSamplingOffset)), lastSampleTime(0ns) { { std::lock_guard threadLock(mThreadMutex); mThread = std::thread([this]() { threadMain(); }); pthread_setname_np(mThread.native_handle(), "RegionSamplingThread"); } mIdleTimer.start(); } RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler) : RegionSamplingThread(flinger, scheduler, TimingTunables{defaultRegionSamplingOffset, defaultRegionSamplingPeriod, defaultRegionSamplingTimerTimeout}) {} RegionSamplingThread::~RegionSamplingThread() { mIdleTimer.stop(); { std::lock_guard lock(mMutex); mRunning = false; Loading Loading @@ -71,8 +212,41 @@ void RegionSamplingThread::removeListener(const sp<IRegionSamplingListener>& lis mDescriptors.erase(wp<IBinder>(IInterface::asBinder(listener))); } void RegionSamplingThread::sampleNow() { void RegionSamplingThread::checkForStaleLuma() { std::lock_guard lock(mMutex); if (mDiscardedFrames) { ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForZeroPhase)); mDiscardedFrames = false; mPhaseCallback->startVsyncListener(); } } void RegionSamplingThread::notifyNewContent() { doSample(); } void RegionSamplingThread::notifySamplingOffset() { doSample(); } void RegionSamplingThread::doSample() { std::lock_guard lock(mMutex); auto now = std::chrono::nanoseconds(systemTime(SYSTEM_TIME_MONOTONIC)); if (lastSampleTime + mTunables.mSamplingPeriod > now) { ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::idleTimerWaiting)); mDiscardedFrames = true; return; } ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::sample)); mDiscardedFrames = false; lastSampleTime = now; mIdleTimer.reset(); mPhaseCallback->stopVsyncListener(); mSampleRequested = true; mCondition.notify_one(); } Loading Loading @@ -238,6 +412,7 @@ void RegionSamplingThread::captureSample() { for (size_t d = 0; d < activeDescriptors.size(); ++d) { activeDescriptors[d].listener->onSampleCollected(lumas[d]); } ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::noWorkNeeded)); } void RegionSamplingThread::threadMain() { Loading
services/surfaceflinger/RegionSamplingThread.h +43 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include <chrono> #include <condition_variable> #include <mutex> #include <thread> Loading @@ -25,17 +26,42 @@ #include <binder/IBinder.h> #include <ui/Rect.h> #include <utils/StrongPointer.h> #include "Scheduler/IdleTimer.h" namespace android { class GraphicBuffer; class IRegionSamplingListener; class Layer; class Scheduler; class SurfaceFlinger; struct SamplingOffsetCallback; class RegionSamplingThread : public IBinder::DeathRecipient { public: explicit RegionSamplingThread(SurfaceFlinger& flinger); struct TimingTunables { // debug.sf.sampling_offset_ns // When asynchronously collecting sample, the offset, from zero phase in the vsync timeline // at which the sampling should start. std::chrono::nanoseconds mSamplingOffset; // debug.sf.sampling_period_ns // This is the maximum amount of time the luma recieving client // should have to wait for a new luma value after a frame is updated. The inverse of this is // roughly the sampling rate. Sampling system rounds up sub-vsync sampling period to vsync // period. std::chrono::nanoseconds mSamplingPeriod; // debug.sf.sampling_timer_timeout_ns // This is the interval at which the luma sampling system will check that the luma clients // have up to date information. It defaults to the mSamplingPeriod. std::chrono::nanoseconds mSamplingTimerTimeout; }; struct EnvironmentTimingTunables : TimingTunables { EnvironmentTimingTunables(); }; explicit RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler, const TimingTunables& tunables); explicit RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler); ~RegionSamplingThread(); // Add a listener to receive luma notifications. The luma reported via listener will Loading @@ -44,8 +70,13 @@ public: const sp<IRegionSamplingListener>& listener); // Remove the listener to stop receiving median luma notifications. void removeListener(const sp<IRegionSamplingListener>& listener); // Instruct the thread to perform a median luma sampling on the layers. void sampleNow(); // Notifies sampling engine that new content is available. This will trigger a sampling // pass at some point in the future. void notifyNewContent(); // Notifies the sampling engine that it has a good timing window in which to sample. void notifySamplingOffset(); private: struct Descriptor { Loading @@ -63,12 +94,19 @@ private: const sp<GraphicBuffer>& buffer, const Point& leftTop, const std::vector<RegionSamplingThread::Descriptor>& descriptors); void doSample(); void binderDied(const wp<IBinder>& who) override; void checkForStaleLuma(); void captureSample() REQUIRES(mMutex); void threadMain(); SurfaceFlinger& mFlinger; Scheduler& mScheduler; const TimingTunables mTunables; scheduler::IdleTimer mIdleTimer; std::unique_ptr<SamplingOffsetCallback> const mPhaseCallback; std::mutex mThreadMutex; std::thread mThread GUARDED_BY(mThreadMutex); Loading @@ -79,6 +117,8 @@ private: bool mSampleRequested GUARDED_BY(mMutex) = false; std::unordered_map<wp<IBinder>, Descriptor, WpHash> mDescriptors GUARDED_BY(mMutex); std::chrono::nanoseconds lastSampleTime GUARDED_BY(mMutex); bool mDiscardedFrames GUARDED_BY(mMutex) = false; }; } // namespace android
services/surfaceflinger/Scheduler/Scheduler.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -304,6 +304,10 @@ void Scheduler::addNativeWindowApi(int apiId) { mApiHistoryCounter = mApiHistoryCounter % scheduler::ARRAY_SIZE; } void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) { fn(*mPrimaryDispSync); } void Scheduler::updateFpsBasedOnNativeWindowApi() { int mode; { Loading
services/surfaceflinger/Scheduler/Scheduler.h +4 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #pragma once #include <cstdint> #include <functional> #include <memory> #include <ui/DisplayStatInfo.h> Loading Loading @@ -104,6 +105,9 @@ public: // Getter methods. EventThread* getEventThread(const sp<ConnectionHandle>& handle); // Provides access to the DispSync object for the primary display. void withPrimaryDispSync(std::function<void(DispSync&)> const& fn); sp<EventThreadConnection> getEventConnection(const sp<ConnectionHandle>& handle); // Should be called when receiving a hotplug event. Loading
services/surfaceflinger/SurfaceFlinger.cpp +6 −2 Original line number Diff line number Diff line Loading @@ -637,6 +637,10 @@ void SurfaceFlinger::init() { mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(), mSfConnectionHandle.get()); mRegionSamplingThread = new RegionSamplingThread(*this, *mScheduler, RegionSamplingThread::EnvironmentTimingTunables()); // Get a RenderEngine for the given display / config (can't fail) int32_t renderEngineFeature = 0; renderEngineFeature |= (useColorManagement ? Loading Loading @@ -2063,8 +2067,8 @@ void SurfaceFlinger::postComposition() mTransactionCompletedThread.addPresentFence(mPreviousPresentFence); mTransactionCompletedThread.sendCallbacks(); if (mLumaSampling) { mRegionSamplingThread->sampleNow(); if (mLumaSampling && mRegionSamplingThread) { mRegionSamplingThread->notifyNewContent(); } } Loading