/* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include "Scheduler/OneShotTimer.h" namespace android { class IRegionSamplingListener; class Layer; class Scheduler; class SurfaceFlinger; struct SamplingOffsetCallback; float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t stride, uint32_t orientation, const Rect& area); class RegionSamplingThread : public IBinder::DeathRecipient { public: 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 // report the median luma for the layers under the stopLayerHandle, in the samplingArea region. void addListener(const Rect& samplingArea, const wp& stopLayer, const sp& listener); // Remove the listener to stop receiving median luma notifications. void removeListener(const sp& listener); // 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 { Rect area = Rect::EMPTY_RECT; wp stopLayer; sp listener; }; struct WpHash { size_t operator()(const wp& p) const { return std::hash()(p.unsafe_get()); } }; std::vector sampleBuffer( const sp& buffer, const Point& leftTop, const std::vector& descriptors, uint32_t orientation); void doSample(); void binderDied(const wp& who) override; void checkForStaleLuma(); void captureSample(); void threadMain(); SurfaceFlinger& mFlinger; Scheduler& mScheduler; const TimingTunables mTunables; scheduler::OneShotTimer mIdleTimer; std::unique_ptr const mPhaseCallback; std::thread mThread; std::mutex mThreadControlMutex; std::condition_variable_any mCondition; bool mRunning GUARDED_BY(mThreadControlMutex) = true; bool mSampleRequested GUARDED_BY(mThreadControlMutex) = false; uint32_t mDiscardedFrames GUARDED_BY(mThreadControlMutex) = 0; std::chrono::nanoseconds lastSampleTime GUARDED_BY(mThreadControlMutex); std::mutex mSamplingMutex; std::unordered_map, Descriptor, WpHash> mDescriptors GUARDED_BY(mSamplingMutex); sp mCachedBuffer GUARDED_BY(mSamplingMutex) = nullptr; }; } // namespace android