diff options
| author | 2021-10-06 22:53:36 +0000 | |
|---|---|---|
| committer | 2021-10-06 22:53:36 +0000 | |
| commit | 097d2a50873100486d65a69cb1cbabf37fb3b188 (patch) | |
| tree | c2f19f92e4503b2de0afeebdd9bf7aeb1bb2e9c1 /services/surfaceflinger/RegionSamplingThread.cpp | |
| parent | cbfb18e134845deeace954bbba818acda48cb80f (diff) | |
| parent | adcb6a2733c1baf66e5ad72365965ab504f5f959 (diff) | |
Merge Android 12
Bug: 202323961
Merged-In: Ifb27b3eb12454fa96f07e6797745c697b4f831c4
Change-Id: I2a7f5931477fddb51564c2eabcdc96ce58888ce8
Diffstat (limited to 'services/surfaceflinger/RegionSamplingThread.cpp')
| -rw-r--r-- | services/surfaceflinger/RegionSamplingThread.cpp | 243 | 
1 files changed, 86 insertions, 157 deletions
| diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 27353d8c0b..aa2fec56ad 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -17,6 +17,7 @@  // TODO(b/129481165): remove the #pragma below and fix conversion issues  #pragma clang diagnostic push  #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra"  //#define LOG_NDEBUG 0  #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -28,15 +29,18 @@  #include <compositionengine/Display.h>  #include <compositionengine/impl/OutputCompositionState.h>  #include <cutils/properties.h> +#include <ftl/future.h>  #include <gui/IRegionSamplingListener.h> +#include <gui/SyncScreenCaptureListener.h>  #include <ui/DisplayStatInfo.h>  #include <utils/Trace.h>  #include <string>  #include "DisplayDevice.h" +#include "DisplayRenderArea.h"  #include "Layer.h" -#include "Scheduler/DispSync.h" +#include "Scheduler/VsyncController.h"  #include "SurfaceFlinger.h"  namespace android { @@ -52,16 +56,14 @@ enum class samplingStep {      noWorkNeeded,      idleTimerWaiting,      waitForQuietFrame, -    waitForZeroPhase,      waitForSamplePhase,      sample  }; -constexpr auto timeForRegionSampling = 5000000ns; -constexpr auto maxRegionSamplingSkips = 10; -constexpr auto defaultRegionSamplingOffset = -3ms; +constexpr auto defaultRegionSamplingWorkDuration = 3ms;  constexpr auto defaultRegionSamplingPeriod = 100ms;  constexpr auto defaultRegionSamplingTimerTimeout = 100ms; +constexpr auto maxRegionSamplingDelay = 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) { @@ -71,9 +73,9 @@ inline std::string toNsString(std::chrono::duration<Rep, Per> t) {  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_duration_ns", value, +                 toNsString(defaultRegionSamplingWorkDuration).c_str()); +    int const samplingDurationNsRaw = atoi(value);      property_get("debug.sf.region_sampling_period_ns", value,                   toNsString(defaultRegionSamplingPeriod).c_str()); @@ -85,103 +87,33 @@ RegionSamplingThread::EnvironmentTimingTunables::EnvironmentTimingTunables() {      if ((samplingPeriodNsRaw < 0) || (samplingTimerTimeoutNsRaw < 0)) {          ALOGW("User-specified sampling tuning options nonsensical. Using defaults"); -        mSamplingOffset = defaultRegionSamplingOffset; +        mSamplingDuration = defaultRegionSamplingWorkDuration;          mSamplingPeriod = defaultRegionSamplingPeriod;          mSamplingTimerTimeout = defaultRegionSamplingTimerTimeout;      } else { -        mSamplingOffset = std::chrono::nanoseconds(samplingOffsetNsRaw); +        mSamplingDuration = std::chrono::nanoseconds(samplingDurationNsRaw);          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.getPrimaryDispSync().addEventListener("SamplingThreadDispSyncListener", 0, this, -                                                         mLastCallbackTime); -        mVsyncListening = true; -    } - -    void stopVsyncListener() { -        std::lock_guard lock(mMutex); -        stopVsyncListenerLocked(); -    } - -private: -    void stopVsyncListenerLocked() /*REQUIRES(mMutex)*/ { -        if (!mVsyncListening) return; - -        mScheduler.getPrimaryDispSync().removeEventListener(this, &mLastCallbackTime); -        mVsyncListening = false; -    } - -    void onDispSyncEvent(nsecs_t /*when*/, nsecs_t /*expectedVSyncTimestamp*/) final { -        std::unique_lock<decltype(mMutex)> lock(mMutex); - -        if (mPhaseIntervalSetting == Phase::ZERO) { -            ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForSamplePhase)); -            mPhaseIntervalSetting = Phase::SAMPLING; -            mScheduler.getPrimaryDispSync().changePhaseOffset(this, mTargetSamplingOffset.count()); -            return; -        } - -        if (mPhaseIntervalSetting == Phase::SAMPLING) { -            mPhaseIntervalSetting = Phase::ZERO; -            mScheduler.getPrimaryDispSync().changePhaseOffset(this, 0); -            stopVsyncListenerLocked(); -            lock.unlock(); -            mRegionSamplingThread.notifySamplingOffset(); -            return; -        } -    } - -    RegionSamplingThread& mRegionSamplingThread; -    Scheduler& mScheduler; -    const std::chrono::nanoseconds mTargetSamplingOffset; -    mutable std::mutex mMutex; -    nsecs_t mLastCallbackTime = 0; -    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) +RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, 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) { +        mIdleTimer( +                "RegSampIdle", +                std::chrono::duration_cast<std::chrono::milliseconds>( +                        mTunables.mSamplingTimerTimeout), +                [] {}, [this] { checkForStaleLuma(); }), +        mLastSampleTime(0ns) {      mThread = std::thread([this]() { threadMain(); }); -    pthread_setname_np(mThread.native_handle(), "RegionSamplingThread"); +    pthread_setname_np(mThread.native_handle(), "RegionSampling");      mIdleTimer.start();  } -RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler) -      : RegionSamplingThread(flinger, scheduler, -                             TimingTunables{defaultRegionSamplingOffset, +RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger) +      : RegionSamplingThread(flinger, +                             TimingTunables{defaultRegionSamplingWorkDuration,                                              defaultRegionSamplingPeriod,                                              defaultRegionSamplingTimerTimeout}) {} @@ -215,49 +147,46 @@ void RegionSamplingThread::removeListener(const sp<IRegionSamplingListener>& lis  void RegionSamplingThread::checkForStaleLuma() {      std::lock_guard lock(mThreadControlMutex); -    if (mDiscardedFrames > 0) { -        ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForZeroPhase)); -        mDiscardedFrames = 0; -        mPhaseCallback->startVsyncListener(); +    if (mSampleRequestTime.has_value()) { +        ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForSamplePhase)); +        mSampleRequestTime.reset(); +        mFlinger.scheduleRegionSamplingThread();      }  } -void RegionSamplingThread::notifyNewContent() { -    doSample(); +void RegionSamplingThread::onCompositionComplete( +        std::optional<std::chrono::steady_clock::time_point> samplingDeadline) { +    doSample(samplingDeadline);  } -void RegionSamplingThread::notifySamplingOffset() { -    doSample(); -} - -void RegionSamplingThread::doSample() { +void RegionSamplingThread::doSample( +        std::optional<std::chrono::steady_clock::time_point> samplingDeadline) {      std::lock_guard lock(mThreadControlMutex); -    auto now = std::chrono::nanoseconds(systemTime(SYSTEM_TIME_MONOTONIC)); -    if (lastSampleTime + mTunables.mSamplingPeriod > now) { +    const auto now = std::chrono::steady_clock::now(); +    if (mLastSampleTime + mTunables.mSamplingPeriod > now) { +        // content changed, but we sampled not too long ago, so we need to sample some time in the +        // future.          ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::idleTimerWaiting)); -        if (mDiscardedFrames == 0) mDiscardedFrames++; +        mSampleRequestTime = now;          return;      } -    if (mDiscardedFrames < maxRegionSamplingSkips) { +    if (!mSampleRequestTime.has_value() || now - *mSampleRequestTime < maxRegionSamplingDelay) {          // If there is relatively little time left for surfaceflinger          // until the next vsync deadline, defer this sampling work          // to a later frame, when hopefully there will be more time. -        DisplayStatInfo stats; -        mScheduler.getDisplayStatInfo(&stats); -        if (std::chrono::nanoseconds(stats.vsyncTime) - now < timeForRegionSampling) { +        if (samplingDeadline.has_value() && now + mTunables.mSamplingDuration > *samplingDeadline) {              ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForQuietFrame)); -            mDiscardedFrames++; +            mSampleRequestTime = mSampleRequestTime.value_or(now);              return;          }      }      ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::sample)); -    mDiscardedFrames = 0; -    lastSampleTime = now; +    mSampleRequestTime.reset(); +    mLastSampleTime = now;      mIdleTimer.reset(); -    mPhaseCallback->stopVsyncListener();      mSampleRequested = true;      mCondition.notify_one(); @@ -336,8 +265,20 @@ void RegionSamplingThread::captureSample() {          return;      } -    const auto device = mFlinger.getDefaultDisplayDevice(); -    const auto orientation = ui::Transform::toRotationFlags(device->getOrientation()); +    wp<const DisplayDevice> displayWeak; + +    ui::LayerStack layerStack; +    ui::Transform::RotationFlags orientation; +    ui::Size displaySize; + +    { +        // TODO(b/159112860): Don't keep sp<DisplayDevice> outside of SF main thread +        const sp<const DisplayDevice> display = mFlinger.getDefaultDisplayDevice(); +        displayWeak = display; +        layerStack = display->getLayerStack(); +        orientation = ui::Transform::toRotationFlags(display->getOrientation()); +        displaySize = display->getSize(); +    }      std::vector<RegionSamplingThread::Descriptor> descriptors;      Region sampleRegion; @@ -346,30 +287,13 @@ void RegionSamplingThread::captureSample() {          descriptors.emplace_back(descriptor);      } -    const Rect sampledArea = sampleRegion.bounds(); - -    auto dx = 0; -    auto dy = 0; -    switch (orientation) { -        case ui::Transform::ROT_90: -            dx = device->getWidth(); -            break; -        case ui::Transform::ROT_180: -            dx = device->getWidth(); -            dy = device->getHeight(); -            break; -        case ui::Transform::ROT_270: -            dy = device->getHeight(); -            break; -        default: -            break; -    } +    const Rect sampledBounds = sampleRegion.bounds(); +    constexpr bool kUseIdentityTransform = false; -    ui::Transform t(orientation); -    auto screencapRegion = t.transform(sampleRegion); -    screencapRegion = screencapRegion.translate(dx, dy); -    DisplayRenderArea renderArea(device, screencapRegion.bounds(), sampledArea.getWidth(), -                                 sampledArea.getHeight(), ui::Dataspace::V0_SRGB, orientation); +    SurfaceFlinger::RenderAreaFuture renderAreaFuture = ftl::defer([=] { +        return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(), +                                         ui::Dataspace::V0_SRGB, kUseIdentityTransform); +    });      std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners; @@ -393,9 +317,9 @@ void RegionSamplingThread::captureSample() {              constexpr bool roundOutwards = true;              Rect transformed = transform.transform(bounds, roundOutwards); -            // If this layer doesn't intersect with the larger sampledArea, skip capturing it +            // If this layer doesn't intersect with the larger sampledBounds, skip capturing it              Rect ignore; -            if (!transformed.intersect(sampledArea, &ignore)) return; +            if (!transformed.intersect(sampledBounds, &ignore)) return;              // If the layer doesn't intersect a sampling area, skip capturing it              bool intersectsAnyArea = false; @@ -411,22 +335,31 @@ void RegionSamplingThread::captureSample() {                    bounds.top, bounds.right, bounds.bottom);              visitor(layer);          }; -        mFlinger.traverseLayersInDisplay(device, filterVisitor); +        mFlinger.traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, filterVisitor);      }; -    sp<GraphicBuffer> buffer = nullptr; -    if (mCachedBuffer && mCachedBuffer->getWidth() == sampledArea.getWidth() && -        mCachedBuffer->getHeight() == sampledArea.getHeight()) { +    std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr; +    if (mCachedBuffer && mCachedBuffer->getBuffer()->getWidth() == sampledBounds.getWidth() && +        mCachedBuffer->getBuffer()->getHeight() == sampledBounds.getHeight()) {          buffer = mCachedBuffer;      } else { -        const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER; -        buffer = new GraphicBuffer(sampledArea.getWidth(), sampledArea.getHeight(), -                                   PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); +        const uint32_t usage = +                GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; +        sp<GraphicBuffer> graphicBuffer = +                new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), +                                  PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); +        const status_t bufferStatus = graphicBuffer->initCheck(); +        LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d", +                            bufferStatus); +        buffer = std::make_shared< +                renderengine::ExternalTexture>(graphicBuffer, mFlinger.getRenderEngine(), +                                               renderengine::ExternalTexture::Usage::WRITEABLE);      } -    bool ignored; -    mFlinger.captureScreenCommon(renderArea, traverseLayers, buffer, false /* identityTransform */, -                                 true /* regionSampling */, ignored); +    const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); +    mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, +                                 true /* regionSampling */, false /* grayscale */, captureListener); +    ScreenCaptureResults captureResults = captureListener->waitForResults();      std::vector<Descriptor> activeDescriptors;      for (const auto& descriptor : descriptors) { @@ -436,8 +369,8 @@ void RegionSamplingThread::captureSample() {      }      ALOGV("Sampling %zu descriptors", activeDescriptors.size()); -    std::vector<float> lumas = -            sampleBuffer(buffer, sampledArea.leftTop(), activeDescriptors, orientation); +    std::vector<float> lumas = sampleBuffer(buffer->getBuffer(), sampledBounds.leftTop(), +                                            activeDescriptors, orientation);      if (lumas.size() != activeDescriptors.size()) {          ALOGW("collected %zu median luma values for %zu descriptors", lumas.size(),                activeDescriptors.size()); @@ -448,10 +381,6 @@ void RegionSamplingThread::captureSample() {          activeDescriptors[d].listener->onSampleCollected(lumas[d]);      } -    // Extend the lifetime of mCachedBuffer from the previous frame to here to ensure that: -    // 1) The region sampling thread is the last owner of the buffer, and the freeing of the buffer -    // happens in this thread, as opposed to the main thread. -    // 2) The listener(s) receive their notifications prior to freeing the buffer.      mCachedBuffer = buffer;      ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::noWorkNeeded));  } @@ -475,4 +404,4 @@ void RegionSamplingThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {  } // namespace android  // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" |