1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker * Copyright 2019 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker *
4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker *
8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker *
10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker */
16*38e8c45fSAndroid Build Coastguard Worker
17*38e8c45fSAndroid Build Coastguard Worker // TODO(b/129481165): remove the #pragma below and fix conversion issues
18*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic push
19*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wconversion"
20*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wextra"
21*38e8c45fSAndroid Build Coastguard Worker
22*38e8c45fSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
23*38e8c45fSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_GRAPHICS
24*38e8c45fSAndroid Build Coastguard Worker #undef LOG_TAG
25*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "RegionSamplingThread"
26*38e8c45fSAndroid Build Coastguard Worker
27*38e8c45fSAndroid Build Coastguard Worker #include "RegionSamplingThread.h"
28*38e8c45fSAndroid Build Coastguard Worker
29*38e8c45fSAndroid Build Coastguard Worker #include <common/trace.h>
30*38e8c45fSAndroid Build Coastguard Worker #include <compositionengine/Display.h>
31*38e8c45fSAndroid Build Coastguard Worker #include <compositionengine/impl/OutputCompositionState.h>
32*38e8c45fSAndroid Build Coastguard Worker #include <cutils/properties.h>
33*38e8c45fSAndroid Build Coastguard Worker #include <ftl/future.h>
34*38e8c45fSAndroid Build Coastguard Worker #include <gui/SpHash.h>
35*38e8c45fSAndroid Build Coastguard Worker #include <gui/SyncScreenCaptureListener.h>
36*38e8c45fSAndroid Build Coastguard Worker #include <renderengine/impl/ExternalTexture.h>
37*38e8c45fSAndroid Build Coastguard Worker #include <ui/DisplayStatInfo.h>
38*38e8c45fSAndroid Build Coastguard Worker
39*38e8c45fSAndroid Build Coastguard Worker #include <string>
40*38e8c45fSAndroid Build Coastguard Worker
41*38e8c45fSAndroid Build Coastguard Worker #include "DisplayDevice.h"
42*38e8c45fSAndroid Build Coastguard Worker #include "DisplayRenderArea.h"
43*38e8c45fSAndroid Build Coastguard Worker #include "FrontEnd/LayerCreationArgs.h"
44*38e8c45fSAndroid Build Coastguard Worker #include "Layer.h"
45*38e8c45fSAndroid Build Coastguard Worker #include "RenderAreaBuilder.h"
46*38e8c45fSAndroid Build Coastguard Worker #include "Scheduler/VsyncController.h"
47*38e8c45fSAndroid Build Coastguard Worker #include "SurfaceFlinger.h"
48*38e8c45fSAndroid Build Coastguard Worker
49*38e8c45fSAndroid Build Coastguard Worker namespace android {
50*38e8c45fSAndroid Build Coastguard Worker using namespace std::chrono_literals;
51*38e8c45fSAndroid Build Coastguard Worker
52*38e8c45fSAndroid Build Coastguard Worker using gui::SpHash;
53*38e8c45fSAndroid Build Coastguard Worker
54*38e8c45fSAndroid Build Coastguard Worker constexpr auto lumaSamplingStepTag = "LumaSamplingStep";
55*38e8c45fSAndroid Build Coastguard Worker enum class samplingStep {
56*38e8c45fSAndroid Build Coastguard Worker noWorkNeeded,
57*38e8c45fSAndroid Build Coastguard Worker idleTimerWaiting,
58*38e8c45fSAndroid Build Coastguard Worker waitForQuietFrame,
59*38e8c45fSAndroid Build Coastguard Worker waitForSamplePhase,
60*38e8c45fSAndroid Build Coastguard Worker sample
61*38e8c45fSAndroid Build Coastguard Worker };
62*38e8c45fSAndroid Build Coastguard Worker
63*38e8c45fSAndroid Build Coastguard Worker constexpr auto defaultRegionSamplingWorkDuration = 3ms;
64*38e8c45fSAndroid Build Coastguard Worker constexpr auto defaultRegionSamplingPeriod = 100ms;
65*38e8c45fSAndroid Build Coastguard Worker constexpr auto defaultRegionSamplingTimerTimeout = 100ms;
66*38e8c45fSAndroid Build Coastguard Worker constexpr auto maxRegionSamplingDelay = 100ms;
67*38e8c45fSAndroid Build Coastguard Worker // TODO: (b/127403193) duration to string conversion could probably be constexpr
68*38e8c45fSAndroid Build Coastguard Worker template <typename Rep, typename Per>
toNsString(std::chrono::duration<Rep,Per> t)69*38e8c45fSAndroid Build Coastguard Worker inline std::string toNsString(std::chrono::duration<Rep, Per> t) {
70*38e8c45fSAndroid Build Coastguard Worker return std::to_string(std::chrono::duration_cast<std::chrono::nanoseconds>(t).count());
71*38e8c45fSAndroid Build Coastguard Worker }
72*38e8c45fSAndroid Build Coastguard Worker
EnvironmentTimingTunables()73*38e8c45fSAndroid Build Coastguard Worker RegionSamplingThread::EnvironmentTimingTunables::EnvironmentTimingTunables() {
74*38e8c45fSAndroid Build Coastguard Worker char value[PROPERTY_VALUE_MAX] = {};
75*38e8c45fSAndroid Build Coastguard Worker
76*38e8c45fSAndroid Build Coastguard Worker property_get("debug.sf.region_sampling_duration_ns", value,
77*38e8c45fSAndroid Build Coastguard Worker toNsString(defaultRegionSamplingWorkDuration).c_str());
78*38e8c45fSAndroid Build Coastguard Worker int const samplingDurationNsRaw = atoi(value);
79*38e8c45fSAndroid Build Coastguard Worker
80*38e8c45fSAndroid Build Coastguard Worker property_get("debug.sf.region_sampling_period_ns", value,
81*38e8c45fSAndroid Build Coastguard Worker toNsString(defaultRegionSamplingPeriod).c_str());
82*38e8c45fSAndroid Build Coastguard Worker int const samplingPeriodNsRaw = atoi(value);
83*38e8c45fSAndroid Build Coastguard Worker
84*38e8c45fSAndroid Build Coastguard Worker property_get("debug.sf.region_sampling_timer_timeout_ns", value,
85*38e8c45fSAndroid Build Coastguard Worker toNsString(defaultRegionSamplingTimerTimeout).c_str());
86*38e8c45fSAndroid Build Coastguard Worker int const samplingTimerTimeoutNsRaw = atoi(value);
87*38e8c45fSAndroid Build Coastguard Worker
88*38e8c45fSAndroid Build Coastguard Worker if ((samplingPeriodNsRaw < 0) || (samplingTimerTimeoutNsRaw < 0)) {
89*38e8c45fSAndroid Build Coastguard Worker ALOGW("User-specified sampling tuning options nonsensical. Using defaults");
90*38e8c45fSAndroid Build Coastguard Worker mSamplingDuration = defaultRegionSamplingWorkDuration;
91*38e8c45fSAndroid Build Coastguard Worker mSamplingPeriod = defaultRegionSamplingPeriod;
92*38e8c45fSAndroid Build Coastguard Worker mSamplingTimerTimeout = defaultRegionSamplingTimerTimeout;
93*38e8c45fSAndroid Build Coastguard Worker } else {
94*38e8c45fSAndroid Build Coastguard Worker mSamplingDuration = std::chrono::nanoseconds(samplingDurationNsRaw);
95*38e8c45fSAndroid Build Coastguard Worker mSamplingPeriod = std::chrono::nanoseconds(samplingPeriodNsRaw);
96*38e8c45fSAndroid Build Coastguard Worker mSamplingTimerTimeout = std::chrono::nanoseconds(samplingTimerTimeoutNsRaw);
97*38e8c45fSAndroid Build Coastguard Worker }
98*38e8c45fSAndroid Build Coastguard Worker }
99*38e8c45fSAndroid Build Coastguard Worker
RegionSamplingThread(SurfaceFlinger & flinger,const TimingTunables & tunables)100*38e8c45fSAndroid Build Coastguard Worker RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, const TimingTunables& tunables)
101*38e8c45fSAndroid Build Coastguard Worker : mFlinger(flinger),
102*38e8c45fSAndroid Build Coastguard Worker mTunables(tunables),
103*38e8c45fSAndroid Build Coastguard Worker mIdleTimer(
104*38e8c45fSAndroid Build Coastguard Worker "RegSampIdle",
105*38e8c45fSAndroid Build Coastguard Worker std::chrono::duration_cast<std::chrono::milliseconds>(
106*38e8c45fSAndroid Build Coastguard Worker mTunables.mSamplingTimerTimeout),
107*38e8c45fSAndroid Build Coastguard Worker [] {}, [this] { checkForStaleLuma(); }),
108*38e8c45fSAndroid Build Coastguard Worker mLastSampleTime(0ns) {
__anon234e33b50302() 109*38e8c45fSAndroid Build Coastguard Worker mThread = std::thread([this]() { threadMain(); });
110*38e8c45fSAndroid Build Coastguard Worker pthread_setname_np(mThread.native_handle(), "RegionSampling");
111*38e8c45fSAndroid Build Coastguard Worker mIdleTimer.start();
112*38e8c45fSAndroid Build Coastguard Worker }
113*38e8c45fSAndroid Build Coastguard Worker
RegionSamplingThread(SurfaceFlinger & flinger)114*38e8c45fSAndroid Build Coastguard Worker RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger)
115*38e8c45fSAndroid Build Coastguard Worker : RegionSamplingThread(flinger,
116*38e8c45fSAndroid Build Coastguard Worker TimingTunables{defaultRegionSamplingWorkDuration,
117*38e8c45fSAndroid Build Coastguard Worker defaultRegionSamplingPeriod,
118*38e8c45fSAndroid Build Coastguard Worker defaultRegionSamplingTimerTimeout}) {}
119*38e8c45fSAndroid Build Coastguard Worker
~RegionSamplingThread()120*38e8c45fSAndroid Build Coastguard Worker RegionSamplingThread::~RegionSamplingThread() {
121*38e8c45fSAndroid Build Coastguard Worker mIdleTimer.stop();
122*38e8c45fSAndroid Build Coastguard Worker
123*38e8c45fSAndroid Build Coastguard Worker {
124*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mThreadControlMutex);
125*38e8c45fSAndroid Build Coastguard Worker mRunning = false;
126*38e8c45fSAndroid Build Coastguard Worker mCondition.notify_one();
127*38e8c45fSAndroid Build Coastguard Worker }
128*38e8c45fSAndroid Build Coastguard Worker
129*38e8c45fSAndroid Build Coastguard Worker if (mThread.joinable()) {
130*38e8c45fSAndroid Build Coastguard Worker mThread.join();
131*38e8c45fSAndroid Build Coastguard Worker }
132*38e8c45fSAndroid Build Coastguard Worker }
133*38e8c45fSAndroid Build Coastguard Worker
addListener(const Rect & samplingArea,uint32_t stopLayerId,const sp<IRegionSamplingListener> & listener)134*38e8c45fSAndroid Build Coastguard Worker void RegionSamplingThread::addListener(const Rect& samplingArea, uint32_t stopLayerId,
135*38e8c45fSAndroid Build Coastguard Worker const sp<IRegionSamplingListener>& listener) {
136*38e8c45fSAndroid Build Coastguard Worker sp<IBinder> asBinder = IInterface::asBinder(listener);
137*38e8c45fSAndroid Build Coastguard Worker asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
138*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mSamplingMutex);
139*38e8c45fSAndroid Build Coastguard Worker mDescriptors.emplace(wp<IBinder>(asBinder), Descriptor{samplingArea, stopLayerId, listener});
140*38e8c45fSAndroid Build Coastguard Worker }
141*38e8c45fSAndroid Build Coastguard Worker
removeListener(const sp<IRegionSamplingListener> & listener)142*38e8c45fSAndroid Build Coastguard Worker void RegionSamplingThread::removeListener(const sp<IRegionSamplingListener>& listener) {
143*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mSamplingMutex);
144*38e8c45fSAndroid Build Coastguard Worker mDescriptors.erase(wp<IBinder>(IInterface::asBinder(listener)));
145*38e8c45fSAndroid Build Coastguard Worker }
146*38e8c45fSAndroid Build Coastguard Worker
checkForStaleLuma()147*38e8c45fSAndroid Build Coastguard Worker void RegionSamplingThread::checkForStaleLuma() {
148*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mThreadControlMutex);
149*38e8c45fSAndroid Build Coastguard Worker
150*38e8c45fSAndroid Build Coastguard Worker if (mSampleRequestTime.has_value()) {
151*38e8c45fSAndroid Build Coastguard Worker SFTRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForSamplePhase));
152*38e8c45fSAndroid Build Coastguard Worker mSampleRequestTime.reset();
153*38e8c45fSAndroid Build Coastguard Worker mFlinger.scheduleSample();
154*38e8c45fSAndroid Build Coastguard Worker }
155*38e8c45fSAndroid Build Coastguard Worker }
156*38e8c45fSAndroid Build Coastguard Worker
onCompositionComplete(std::optional<std::chrono::steady_clock::time_point> samplingDeadline)157*38e8c45fSAndroid Build Coastguard Worker void RegionSamplingThread::onCompositionComplete(
158*38e8c45fSAndroid Build Coastguard Worker std::optional<std::chrono::steady_clock::time_point> samplingDeadline) {
159*38e8c45fSAndroid Build Coastguard Worker doSample(samplingDeadline);
160*38e8c45fSAndroid Build Coastguard Worker }
161*38e8c45fSAndroid Build Coastguard Worker
doSample(std::optional<std::chrono::steady_clock::time_point> samplingDeadline)162*38e8c45fSAndroid Build Coastguard Worker void RegionSamplingThread::doSample(
163*38e8c45fSAndroid Build Coastguard Worker std::optional<std::chrono::steady_clock::time_point> samplingDeadline) {
164*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mThreadControlMutex);
165*38e8c45fSAndroid Build Coastguard Worker const auto now = std::chrono::steady_clock::now();
166*38e8c45fSAndroid Build Coastguard Worker if (mLastSampleTime + mTunables.mSamplingPeriod > now) {
167*38e8c45fSAndroid Build Coastguard Worker // content changed, but we sampled not too long ago, so we need to sample some time in the
168*38e8c45fSAndroid Build Coastguard Worker // future.
169*38e8c45fSAndroid Build Coastguard Worker SFTRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::idleTimerWaiting));
170*38e8c45fSAndroid Build Coastguard Worker mSampleRequestTime = now;
171*38e8c45fSAndroid Build Coastguard Worker return;
172*38e8c45fSAndroid Build Coastguard Worker }
173*38e8c45fSAndroid Build Coastguard Worker if (!mSampleRequestTime.has_value() || now - *mSampleRequestTime < maxRegionSamplingDelay) {
174*38e8c45fSAndroid Build Coastguard Worker // If there is relatively little time left for surfaceflinger
175*38e8c45fSAndroid Build Coastguard Worker // until the next vsync deadline, defer this sampling work
176*38e8c45fSAndroid Build Coastguard Worker // to a later frame, when hopefully there will be more time.
177*38e8c45fSAndroid Build Coastguard Worker if (samplingDeadline.has_value() && now + mTunables.mSamplingDuration > *samplingDeadline) {
178*38e8c45fSAndroid Build Coastguard Worker SFTRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForQuietFrame));
179*38e8c45fSAndroid Build Coastguard Worker mSampleRequestTime = mSampleRequestTime.value_or(now);
180*38e8c45fSAndroid Build Coastguard Worker return;
181*38e8c45fSAndroid Build Coastguard Worker }
182*38e8c45fSAndroid Build Coastguard Worker }
183*38e8c45fSAndroid Build Coastguard Worker
184*38e8c45fSAndroid Build Coastguard Worker SFTRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::sample));
185*38e8c45fSAndroid Build Coastguard Worker
186*38e8c45fSAndroid Build Coastguard Worker mSampleRequestTime.reset();
187*38e8c45fSAndroid Build Coastguard Worker mLastSampleTime = now;
188*38e8c45fSAndroid Build Coastguard Worker
189*38e8c45fSAndroid Build Coastguard Worker mIdleTimer.reset();
190*38e8c45fSAndroid Build Coastguard Worker
191*38e8c45fSAndroid Build Coastguard Worker mSampleRequested = true;
192*38e8c45fSAndroid Build Coastguard Worker mCondition.notify_one();
193*38e8c45fSAndroid Build Coastguard Worker }
194*38e8c45fSAndroid Build Coastguard Worker
binderDied(const wp<IBinder> & who)195*38e8c45fSAndroid Build Coastguard Worker void RegionSamplingThread::binderDied(const wp<IBinder>& who) {
196*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mSamplingMutex);
197*38e8c45fSAndroid Build Coastguard Worker mDescriptors.erase(who);
198*38e8c45fSAndroid Build Coastguard Worker }
199*38e8c45fSAndroid Build Coastguard Worker
sampleArea(const uint32_t * data,int32_t width,int32_t height,int32_t stride,uint32_t orientation,const Rect & sample_area)200*38e8c45fSAndroid Build Coastguard Worker float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t stride,
201*38e8c45fSAndroid Build Coastguard Worker uint32_t orientation, const Rect& sample_area) {
202*38e8c45fSAndroid Build Coastguard Worker if (!sample_area.isValid() || (sample_area.getWidth() > width) ||
203*38e8c45fSAndroid Build Coastguard Worker (sample_area.getHeight() > height)) {
204*38e8c45fSAndroid Build Coastguard Worker ALOGE("invalid sampling region requested");
205*38e8c45fSAndroid Build Coastguard Worker return 0.0f;
206*38e8c45fSAndroid Build Coastguard Worker }
207*38e8c45fSAndroid Build Coastguard Worker
208*38e8c45fSAndroid Build Coastguard Worker const uint32_t pixelCount =
209*38e8c45fSAndroid Build Coastguard Worker (sample_area.bottom - sample_area.top) * (sample_area.right - sample_area.left);
210*38e8c45fSAndroid Build Coastguard Worker uint32_t accumulatedLuma = 0;
211*38e8c45fSAndroid Build Coastguard Worker
212*38e8c45fSAndroid Build Coastguard Worker // Calculates luma with approximation of Rec. 709 primaries
213*38e8c45fSAndroid Build Coastguard Worker for (int32_t row = sample_area.top; row < sample_area.bottom; ++row) {
214*38e8c45fSAndroid Build Coastguard Worker const uint32_t* rowBase = data + row * stride;
215*38e8c45fSAndroid Build Coastguard Worker for (int32_t column = sample_area.left; column < sample_area.right; ++column) {
216*38e8c45fSAndroid Build Coastguard Worker uint32_t pixel = rowBase[column];
217*38e8c45fSAndroid Build Coastguard Worker const uint32_t r = pixel & 0xFF;
218*38e8c45fSAndroid Build Coastguard Worker const uint32_t g = (pixel >> 8) & 0xFF;
219*38e8c45fSAndroid Build Coastguard Worker const uint32_t b = (pixel >> 16) & 0xFF;
220*38e8c45fSAndroid Build Coastguard Worker const uint32_t luma = (r * 7 + b * 2 + g * 23) >> 5;
221*38e8c45fSAndroid Build Coastguard Worker accumulatedLuma += luma;
222*38e8c45fSAndroid Build Coastguard Worker }
223*38e8c45fSAndroid Build Coastguard Worker }
224*38e8c45fSAndroid Build Coastguard Worker
225*38e8c45fSAndroid Build Coastguard Worker return accumulatedLuma / (255.0f * pixelCount);
226*38e8c45fSAndroid Build Coastguard Worker }
227*38e8c45fSAndroid Build Coastguard Worker
sampleBuffer(const sp<GraphicBuffer> & buffer,const Point & leftTop,const std::vector<RegionSamplingThread::Descriptor> & descriptors,uint32_t orientation)228*38e8c45fSAndroid Build Coastguard Worker std::vector<float> RegionSamplingThread::sampleBuffer(
229*38e8c45fSAndroid Build Coastguard Worker const sp<GraphicBuffer>& buffer, const Point& leftTop,
230*38e8c45fSAndroid Build Coastguard Worker const std::vector<RegionSamplingThread::Descriptor>& descriptors, uint32_t orientation) {
231*38e8c45fSAndroid Build Coastguard Worker void* data_raw = nullptr;
232*38e8c45fSAndroid Build Coastguard Worker buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, &data_raw);
233*38e8c45fSAndroid Build Coastguard Worker std::shared_ptr<uint32_t> data(reinterpret_cast<uint32_t*>(data_raw),
234*38e8c45fSAndroid Build Coastguard Worker [&buffer](auto) { buffer->unlock(); });
235*38e8c45fSAndroid Build Coastguard Worker if (!data) return {};
236*38e8c45fSAndroid Build Coastguard Worker
237*38e8c45fSAndroid Build Coastguard Worker const int32_t width = buffer->getWidth();
238*38e8c45fSAndroid Build Coastguard Worker const int32_t height = buffer->getHeight();
239*38e8c45fSAndroid Build Coastguard Worker const int32_t stride = buffer->getStride();
240*38e8c45fSAndroid Build Coastguard Worker std::vector<float> lumas(descriptors.size());
241*38e8c45fSAndroid Build Coastguard Worker std::transform(descriptors.begin(), descriptors.end(), lumas.begin(),
242*38e8c45fSAndroid Build Coastguard Worker [&](auto const& descriptor) {
243*38e8c45fSAndroid Build Coastguard Worker return sampleArea(data.get(), width, height, stride, orientation,
244*38e8c45fSAndroid Build Coastguard Worker descriptor.area - leftTop);
245*38e8c45fSAndroid Build Coastguard Worker });
246*38e8c45fSAndroid Build Coastguard Worker return lumas;
247*38e8c45fSAndroid Build Coastguard Worker }
248*38e8c45fSAndroid Build Coastguard Worker
captureSample()249*38e8c45fSAndroid Build Coastguard Worker void RegionSamplingThread::captureSample() {
250*38e8c45fSAndroid Build Coastguard Worker SFTRACE_CALL();
251*38e8c45fSAndroid Build Coastguard Worker std::lock_guard lock(mSamplingMutex);
252*38e8c45fSAndroid Build Coastguard Worker
253*38e8c45fSAndroid Build Coastguard Worker if (mDescriptors.empty()) {
254*38e8c45fSAndroid Build Coastguard Worker return;
255*38e8c45fSAndroid Build Coastguard Worker }
256*38e8c45fSAndroid Build Coastguard Worker
257*38e8c45fSAndroid Build Coastguard Worker wp<const DisplayDevice> displayWeak;
258*38e8c45fSAndroid Build Coastguard Worker
259*38e8c45fSAndroid Build Coastguard Worker ui::LayerStack layerStack;
260*38e8c45fSAndroid Build Coastguard Worker ui::Transform::RotationFlags orientation;
261*38e8c45fSAndroid Build Coastguard Worker ui::Size displaySize;
262*38e8c45fSAndroid Build Coastguard Worker
263*38e8c45fSAndroid Build Coastguard Worker {
264*38e8c45fSAndroid Build Coastguard Worker // TODO(b/159112860): Don't keep sp<DisplayDevice> outside of SF main thread
265*38e8c45fSAndroid Build Coastguard Worker const sp<const DisplayDevice> display = mFlinger.getDefaultDisplayDevice();
266*38e8c45fSAndroid Build Coastguard Worker displayWeak = display;
267*38e8c45fSAndroid Build Coastguard Worker layerStack = display->getLayerStack();
268*38e8c45fSAndroid Build Coastguard Worker orientation = ui::Transform::toRotationFlags(display->getOrientation());
269*38e8c45fSAndroid Build Coastguard Worker displaySize = display->getSize();
270*38e8c45fSAndroid Build Coastguard Worker }
271*38e8c45fSAndroid Build Coastguard Worker
272*38e8c45fSAndroid Build Coastguard Worker std::vector<RegionSamplingThread::Descriptor> descriptors;
273*38e8c45fSAndroid Build Coastguard Worker Region sampleRegion;
274*38e8c45fSAndroid Build Coastguard Worker for (const auto& [listener, descriptor] : mDescriptors) {
275*38e8c45fSAndroid Build Coastguard Worker sampleRegion.orSelf(descriptor.area);
276*38e8c45fSAndroid Build Coastguard Worker descriptors.emplace_back(descriptor);
277*38e8c45fSAndroid Build Coastguard Worker }
278*38e8c45fSAndroid Build Coastguard Worker
279*38e8c45fSAndroid Build Coastguard Worker const Rect sampledBounds = sampleRegion.bounds();
280*38e8c45fSAndroid Build Coastguard Worker
281*38e8c45fSAndroid Build Coastguard Worker std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
282*38e8c45fSAndroid Build Coastguard Worker
283*38e8c45fSAndroid Build Coastguard Worker auto layerFilterFn = [&](const char* layerName, uint32_t layerId, const Rect& bounds,
284*38e8c45fSAndroid Build Coastguard Worker const ui::Transform transform, bool& outStopTraversal) -> bool {
285*38e8c45fSAndroid Build Coastguard Worker // Likewise if we just found a stop layer, set the flag and abort
286*38e8c45fSAndroid Build Coastguard Worker for (const auto& [area, stopLayerId, listener] : descriptors) {
287*38e8c45fSAndroid Build Coastguard Worker if (stopLayerId != UNASSIGNED_LAYER_ID && layerId == stopLayerId) {
288*38e8c45fSAndroid Build Coastguard Worker outStopTraversal = true;
289*38e8c45fSAndroid Build Coastguard Worker return false;
290*38e8c45fSAndroid Build Coastguard Worker }
291*38e8c45fSAndroid Build Coastguard Worker }
292*38e8c45fSAndroid Build Coastguard Worker
293*38e8c45fSAndroid Build Coastguard Worker // Compute the layer's position on the screen
294*38e8c45fSAndroid Build Coastguard Worker constexpr bool roundOutwards = true;
295*38e8c45fSAndroid Build Coastguard Worker Rect transformed = transform.transform(bounds, roundOutwards);
296*38e8c45fSAndroid Build Coastguard Worker
297*38e8c45fSAndroid Build Coastguard Worker // If this layer doesn't intersect with the larger sampledBounds, skip capturing it
298*38e8c45fSAndroid Build Coastguard Worker Rect ignore;
299*38e8c45fSAndroid Build Coastguard Worker if (!transformed.intersect(sampledBounds, &ignore)) return false;
300*38e8c45fSAndroid Build Coastguard Worker
301*38e8c45fSAndroid Build Coastguard Worker // If the layer doesn't intersect a sampling area, skip capturing it
302*38e8c45fSAndroid Build Coastguard Worker bool intersectsAnyArea = false;
303*38e8c45fSAndroid Build Coastguard Worker for (const auto& [area, stopLayer, listener] : descriptors) {
304*38e8c45fSAndroid Build Coastguard Worker if (transformed.intersect(area, &ignore)) {
305*38e8c45fSAndroid Build Coastguard Worker intersectsAnyArea = true;
306*38e8c45fSAndroid Build Coastguard Worker listeners.insert(listener);
307*38e8c45fSAndroid Build Coastguard Worker }
308*38e8c45fSAndroid Build Coastguard Worker }
309*38e8c45fSAndroid Build Coastguard Worker if (!intersectsAnyArea) return false;
310*38e8c45fSAndroid Build Coastguard Worker
311*38e8c45fSAndroid Build Coastguard Worker ALOGV("Traversing [%s] [%d, %d, %d, %d]", layerName, bounds.left, bounds.top, bounds.right,
312*38e8c45fSAndroid Build Coastguard Worker bounds.bottom);
313*38e8c45fSAndroid Build Coastguard Worker
314*38e8c45fSAndroid Build Coastguard Worker return true;
315*38e8c45fSAndroid Build Coastguard Worker };
316*38e8c45fSAndroid Build Coastguard Worker
317*38e8c45fSAndroid Build Coastguard Worker auto filterFn = [&](const frontend::LayerSnapshot& snapshot, bool& outStopTraversal) -> bool {
318*38e8c45fSAndroid Build Coastguard Worker const Rect bounds = frontend::RequestedLayerState::reduce(Rect(snapshot.geomLayerBounds),
319*38e8c45fSAndroid Build Coastguard Worker snapshot.transparentRegionHint);
320*38e8c45fSAndroid Build Coastguard Worker const ui::Transform transform = snapshot.geomLayerTransform;
321*38e8c45fSAndroid Build Coastguard Worker return layerFilterFn(snapshot.name.c_str(), snapshot.path.id, bounds, transform,
322*38e8c45fSAndroid Build Coastguard Worker outStopTraversal);
323*38e8c45fSAndroid Build Coastguard Worker };
324*38e8c45fSAndroid Build Coastguard Worker auto getLayerSnapshotsFn =
325*38e8c45fSAndroid Build Coastguard Worker mFlinger.getLayerSnapshotsForScreenshots(layerStack, CaptureArgs::UNSET_UID, filterFn);
326*38e8c45fSAndroid Build Coastguard Worker
327*38e8c45fSAndroid Build Coastguard Worker std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr;
328*38e8c45fSAndroid Build Coastguard Worker if (mCachedBuffer && mCachedBuffer->getBuffer()->getWidth() == sampledBounds.getWidth() &&
329*38e8c45fSAndroid Build Coastguard Worker mCachedBuffer->getBuffer()->getHeight() == sampledBounds.getHeight()) {
330*38e8c45fSAndroid Build Coastguard Worker buffer = mCachedBuffer;
331*38e8c45fSAndroid Build Coastguard Worker } else {
332*38e8c45fSAndroid Build Coastguard Worker const uint32_t usage =
333*38e8c45fSAndroid Build Coastguard Worker GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
334*38e8c45fSAndroid Build Coastguard Worker sp<GraphicBuffer> graphicBuffer =
335*38e8c45fSAndroid Build Coastguard Worker sp<GraphicBuffer>::make(sampledBounds.getWidth(), sampledBounds.getHeight(),
336*38e8c45fSAndroid Build Coastguard Worker PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
337*38e8c45fSAndroid Build Coastguard Worker const status_t bufferStatus = graphicBuffer->initCheck();
338*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d",
339*38e8c45fSAndroid Build Coastguard Worker bufferStatus);
340*38e8c45fSAndroid Build Coastguard Worker buffer = std::make_shared<
341*38e8c45fSAndroid Build Coastguard Worker renderengine::impl::ExternalTexture>(graphicBuffer, mFlinger.getRenderEngine(),
342*38e8c45fSAndroid Build Coastguard Worker renderengine::impl::ExternalTexture::Usage::
343*38e8c45fSAndroid Build Coastguard Worker WRITEABLE);
344*38e8c45fSAndroid Build Coastguard Worker }
345*38e8c45fSAndroid Build Coastguard Worker
346*38e8c45fSAndroid Build Coastguard Worker constexpr bool kRegionSampling = true;
347*38e8c45fSAndroid Build Coastguard Worker constexpr bool kGrayscale = false;
348*38e8c45fSAndroid Build Coastguard Worker constexpr bool kIsProtected = false;
349*38e8c45fSAndroid Build Coastguard Worker constexpr bool kAttachGainmap = false;
350*38e8c45fSAndroid Build Coastguard Worker
351*38e8c45fSAndroid Build Coastguard Worker SurfaceFlinger::RenderAreaBuilderVariant
352*38e8c45fSAndroid Build Coastguard Worker renderAreaBuilder(std::in_place_type<DisplayRenderAreaBuilder>, sampledBounds,
353*38e8c45fSAndroid Build Coastguard Worker sampledBounds.getSize(), ui::Dataspace::V0_SRGB, displayWeak,
354*38e8c45fSAndroid Build Coastguard Worker RenderArea::Options::CAPTURE_SECURE_LAYERS);
355*38e8c45fSAndroid Build Coastguard Worker
356*38e8c45fSAndroid Build Coastguard Worker std::vector<std::pair<Layer*, sp<LayerFE>>> layers;
357*38e8c45fSAndroid Build Coastguard Worker auto displayState =
358*38e8c45fSAndroid Build Coastguard Worker mFlinger.getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layers);
359*38e8c45fSAndroid Build Coastguard Worker FenceResult fenceResult =
360*38e8c45fSAndroid Build Coastguard Worker mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, kGrayscale,
361*38e8c45fSAndroid Build Coastguard Worker kIsProtected, kAttachGainmap, nullptr, displayState, layers)
362*38e8c45fSAndroid Build Coastguard Worker .get();
363*38e8c45fSAndroid Build Coastguard Worker if (fenceResult.ok()) {
364*38e8c45fSAndroid Build Coastguard Worker fenceResult.value()->waitForever(LOG_TAG);
365*38e8c45fSAndroid Build Coastguard Worker }
366*38e8c45fSAndroid Build Coastguard Worker
367*38e8c45fSAndroid Build Coastguard Worker std::vector<Descriptor> activeDescriptors;
368*38e8c45fSAndroid Build Coastguard Worker for (const auto& descriptor : descriptors) {
369*38e8c45fSAndroid Build Coastguard Worker if (listeners.count(descriptor.listener) != 0) {
370*38e8c45fSAndroid Build Coastguard Worker activeDescriptors.emplace_back(descriptor);
371*38e8c45fSAndroid Build Coastguard Worker }
372*38e8c45fSAndroid Build Coastguard Worker }
373*38e8c45fSAndroid Build Coastguard Worker
374*38e8c45fSAndroid Build Coastguard Worker ALOGV("Sampling %zu descriptors", activeDescriptors.size());
375*38e8c45fSAndroid Build Coastguard Worker std::vector<float> lumas = sampleBuffer(buffer->getBuffer(), sampledBounds.leftTop(),
376*38e8c45fSAndroid Build Coastguard Worker activeDescriptors, orientation);
377*38e8c45fSAndroid Build Coastguard Worker if (lumas.size() != activeDescriptors.size()) {
378*38e8c45fSAndroid Build Coastguard Worker ALOGW("collected %zu median luma values for %zu descriptors", lumas.size(),
379*38e8c45fSAndroid Build Coastguard Worker activeDescriptors.size());
380*38e8c45fSAndroid Build Coastguard Worker return;
381*38e8c45fSAndroid Build Coastguard Worker }
382*38e8c45fSAndroid Build Coastguard Worker
383*38e8c45fSAndroid Build Coastguard Worker for (size_t d = 0; d < activeDescriptors.size(); ++d) {
384*38e8c45fSAndroid Build Coastguard Worker activeDescriptors[d].listener->onSampleCollected(lumas[d]);
385*38e8c45fSAndroid Build Coastguard Worker }
386*38e8c45fSAndroid Build Coastguard Worker
387*38e8c45fSAndroid Build Coastguard Worker mCachedBuffer = buffer;
388*38e8c45fSAndroid Build Coastguard Worker SFTRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::noWorkNeeded));
389*38e8c45fSAndroid Build Coastguard Worker }
390*38e8c45fSAndroid Build Coastguard Worker
391*38e8c45fSAndroid Build Coastguard Worker // NO_THREAD_SAFETY_ANALYSIS is because std::unique_lock presently lacks thread safety annotations.
threadMain()392*38e8c45fSAndroid Build Coastguard Worker void RegionSamplingThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
393*38e8c45fSAndroid Build Coastguard Worker std::unique_lock<std::mutex> lock(mThreadControlMutex);
394*38e8c45fSAndroid Build Coastguard Worker while (mRunning) {
395*38e8c45fSAndroid Build Coastguard Worker if (mSampleRequested) {
396*38e8c45fSAndroid Build Coastguard Worker mSampleRequested = false;
397*38e8c45fSAndroid Build Coastguard Worker lock.unlock();
398*38e8c45fSAndroid Build Coastguard Worker captureSample();
399*38e8c45fSAndroid Build Coastguard Worker lock.lock();
400*38e8c45fSAndroid Build Coastguard Worker }
401*38e8c45fSAndroid Build Coastguard Worker mCondition.wait(lock, [this]() REQUIRES(mThreadControlMutex) {
402*38e8c45fSAndroid Build Coastguard Worker return mSampleRequested || !mRunning;
403*38e8c45fSAndroid Build Coastguard Worker });
404*38e8c45fSAndroid Build Coastguard Worker }
405*38e8c45fSAndroid Build Coastguard Worker }
406*38e8c45fSAndroid Build Coastguard Worker
407*38e8c45fSAndroid Build Coastguard Worker } // namespace android
408*38e8c45fSAndroid Build Coastguard Worker
409*38e8c45fSAndroid Build Coastguard Worker // TODO(b/129481165): remove the #pragma below and fix conversion issues
410*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
411