blob: ce7d37e69ba6b847b8d23c00ebe3c59236a0cf8c [file] [log] [blame]
Vishnu Nair8fc721b2022-12-22 20:06:32 +00001/*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// #define LOG_NDEBUG 0
18#define ATRACE_TAG ATRACE_TAG_GRAPHICS
19#undef LOG_TAG
20#define LOG_TAG "LayerSnapshotBuilder"
21
22#include "LayerSnapshotBuilder.h"
23#include <gui/TraceUtils.h>
Vishnu Nairfed7c122023-03-18 01:54:43 +000024#include <ui/FloatRect.h>
Vishnu Nairb76d99a2023-03-19 18:22:31 -070025
Vishnu Nair8fc721b2022-12-22 20:06:32 +000026#include <numeric>
Vishnu Nairb76d99a2023-03-19 18:22:31 -070027#include <optional>
28
29#include <gui/TraceUtils.h>
Vishnu Nair8fc721b2022-12-22 20:06:32 +000030#include "DisplayHardware/HWC2.h"
31#include "DisplayHardware/Hal.h"
Vishnu Naircfb2d252023-01-19 04:44:02 +000032#include "LayerLog.h"
Vishnu Nairb76d99a2023-03-19 18:22:31 -070033#include "LayerSnapshotBuilder.h"
Vishnu Naircfb2d252023-01-19 04:44:02 +000034#include "TimeStats/TimeStats.h"
Vishnu Nair8fc721b2022-12-22 20:06:32 +000035#include "ftl/small_map.h"
36
37namespace android::surfaceflinger::frontend {
38
39using namespace ftl::flag_operators;
40
41namespace {
42FloatRect getMaxDisplayBounds(
43 const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displays) {
44 const ui::Size maxSize = [&displays] {
45 if (displays.empty()) return ui::Size{5000, 5000};
46
47 return std::accumulate(displays.begin(), displays.end(), ui::kEmptySize,
48 [](ui::Size size, const auto& pair) -> ui::Size {
49 const auto& display = pair.second;
50 return {std::max(size.getWidth(), display.info.logicalWidth),
51 std::max(size.getHeight(), display.info.logicalHeight)};
52 });
53 }();
54
55 // Ignore display bounds for now since they will be computed later. Use a large Rect bound
56 // to ensure it's bigger than an actual display will be.
57 const float xMax = static_cast<float>(maxSize.getWidth()) * 10.f;
58 const float yMax = static_cast<float>(maxSize.getHeight()) * 10.f;
59
60 return {-xMax, -yMax, xMax, yMax};
61}
62
63// Applies the given transform to the region, while protecting against overflows caused by any
64// offsets. If applying the offset in the transform to any of the Rects in the region would result
65// in an overflow, they are not added to the output Region.
66Region transformTouchableRegionSafely(const ui::Transform& t, const Region& r,
67 const std::string& debugWindowName) {
68 // Round the translation using the same rounding strategy used by ui::Transform.
69 const auto tx = static_cast<int32_t>(t.tx() + 0.5);
70 const auto ty = static_cast<int32_t>(t.ty() + 0.5);
71
72 ui::Transform transformWithoutOffset = t;
73 transformWithoutOffset.set(0.f, 0.f);
74
75 const Region transformed = transformWithoutOffset.transform(r);
76
77 // Apply the translation to each of the Rects in the region while discarding any that overflow.
78 Region ret;
79 for (const auto& rect : transformed) {
80 Rect newRect;
81 if (__builtin_add_overflow(rect.left, tx, &newRect.left) ||
82 __builtin_add_overflow(rect.top, ty, &newRect.top) ||
83 __builtin_add_overflow(rect.right, tx, &newRect.right) ||
84 __builtin_add_overflow(rect.bottom, ty, &newRect.bottom)) {
85 ALOGE("Applying transform to touchable region of window '%s' resulted in an overflow.",
86 debugWindowName.c_str());
87 continue;
88 }
89 ret.orSelf(newRect);
90 }
91 return ret;
92}
93
94/*
95 * We don't want to send the layer's transform to input, but rather the
96 * parent's transform. This is because Layer's transform is
97 * information about how the buffer is placed on screen. The parent's
98 * transform makes more sense to send since it's information about how the
99 * layer is placed on screen. This transform is used by input to determine
100 * how to go from screen space back to window space.
101 */
102ui::Transform getInputTransform(const LayerSnapshot& snapshot) {
103 if (!snapshot.hasBufferOrSidebandStream()) {
104 return snapshot.geomLayerTransform;
105 }
106 return snapshot.parentTransform;
107}
108
109/**
Vishnu Nairfed7c122023-03-18 01:54:43 +0000110 * Returns the bounds used to fill the input frame and the touchable region.
111 *
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000112 * Similar to getInputTransform, we need to update the bounds to include the transform.
113 * This is because bounds don't include the buffer transform, where the input assumes
114 * that's already included.
115 */
Vishnu Nairfed7c122023-03-18 01:54:43 +0000116std::pair<FloatRect, bool> getInputBounds(const LayerSnapshot& snapshot, bool fillParentBounds) {
117 FloatRect inputBounds = snapshot.croppedBufferSize.toFloatRect();
118 if (snapshot.hasBufferOrSidebandStream() && snapshot.croppedBufferSize.isValid() &&
119 snapshot.localTransform.getType() != ui::Transform::IDENTITY) {
120 inputBounds = snapshot.localTransform.transform(inputBounds);
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000121 }
122
Vishnu Nairfed7c122023-03-18 01:54:43 +0000123 bool inputBoundsValid = snapshot.croppedBufferSize.isValid();
124 if (!inputBoundsValid) {
125 /**
126 * Input bounds are based on the layer crop or buffer size. But if we are using
127 * the layer bounds as the input bounds (replaceTouchableRegionWithCrop flag) then
128 * we can use the parent bounds as the input bounds if the layer does not have buffer
129 * or a crop. We want to unify this logic but because of compat reasons we cannot always
130 * use the parent bounds. A layer without a buffer can get input. So when a window is
131 * initially added, its touchable region can fill its parent layer bounds and that can
132 * have negative consequences.
133 */
134 inputBounds = fillParentBounds ? snapshot.geomLayerBounds : FloatRect{};
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000135 }
Vishnu Nairfed7c122023-03-18 01:54:43 +0000136
137 // Clamp surface inset to the input bounds.
138 const float inset = static_cast<float>(snapshot.inputInfo.surfaceInset);
139 const float xSurfaceInset = std::clamp(inset, 0.f, inputBounds.getWidth() / 2.f);
140 const float ySurfaceInset = std::clamp(inset, 0.f, inputBounds.getHeight() / 2.f);
141
142 // Apply the insets to the input bounds.
143 inputBounds.left += xSurfaceInset;
144 inputBounds.top += ySurfaceInset;
145 inputBounds.right -= xSurfaceInset;
146 inputBounds.bottom -= ySurfaceInset;
147 return {inputBounds, inputBoundsValid};
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000148}
149
Vishnu Nairfed7c122023-03-18 01:54:43 +0000150Rect getInputBoundsInDisplaySpace(const LayerSnapshot& snapshot, const FloatRect& insetBounds,
151 const ui::Transform& screenToDisplay) {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000152 // InputDispatcher works in the display device's coordinate space. Here, we calculate the
153 // frame and transform used for the layer, which determines the bounds and the coordinate space
154 // within which the layer will receive input.
Vishnu Nairfed7c122023-03-18 01:54:43 +0000155
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000156 // Coordinate space definitions:
157 // - display: The display device's coordinate space. Correlates to pixels on the display.
158 // - screen: The post-rotation coordinate space for the display, a.k.a. logical display space.
159 // - layer: The coordinate space of this layer.
160 // - input: The coordinate space in which this layer will receive input events. This could be
161 // different than layer space if a surfaceInset is used, which changes the origin
162 // of the input space.
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000163
164 // Crop the input bounds to ensure it is within the parent's bounds.
Vishnu Nairfed7c122023-03-18 01:54:43 +0000165 const FloatRect croppedInsetBoundsInLayer = snapshot.geomLayerBounds.intersect(insetBounds);
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000166
167 const ui::Transform layerToScreen = getInputTransform(snapshot);
168 const ui::Transform layerToDisplay = screenToDisplay * layerToScreen;
169
Vishnu Nairfed7c122023-03-18 01:54:43 +0000170 return Rect{layerToDisplay.transform(croppedInsetBoundsInLayer)};
171}
172
173void fillInputFrameInfo(gui::WindowInfo& info, const ui::Transform& screenToDisplay,
174 const LayerSnapshot& snapshot) {
175 auto [inputBounds, inputBoundsValid] = getInputBounds(snapshot, /*fillParentBounds=*/false);
176 if (!inputBoundsValid) {
177 info.touchableRegion.clear();
178 }
179
180 const Rect roundedFrameInDisplay =
181 getInputBoundsInDisplaySpace(snapshot, inputBounds, screenToDisplay);
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000182 info.frameLeft = roundedFrameInDisplay.left;
183 info.frameTop = roundedFrameInDisplay.top;
184 info.frameRight = roundedFrameInDisplay.right;
185 info.frameBottom = roundedFrameInDisplay.bottom;
186
187 ui::Transform inputToLayer;
Vishnu Nairfed7c122023-03-18 01:54:43 +0000188 inputToLayer.set(inputBounds.left, inputBounds.top);
189 const ui::Transform layerToScreen = getInputTransform(snapshot);
190 const ui::Transform inputToDisplay = screenToDisplay * layerToScreen * inputToLayer;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000191
192 // InputDispatcher expects a display-to-input transform.
193 info.transform = inputToDisplay.inverse();
194
195 // The touchable region is specified in the input coordinate space. Change it to display space.
196 info.touchableRegion =
197 transformTouchableRegionSafely(inputToDisplay, info.touchableRegion, snapshot.name);
198}
199
200void handleDropInputMode(LayerSnapshot& snapshot, const LayerSnapshot& parentSnapshot) {
201 if (snapshot.inputInfo.inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL)) {
202 return;
203 }
204
205 // Check if we need to drop input unconditionally
206 const gui::DropInputMode dropInputMode = snapshot.dropInputMode;
207 if (dropInputMode == gui::DropInputMode::ALL) {
208 snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::DROP_INPUT;
209 ALOGV("Dropping input for %s as requested by policy.", snapshot.name.c_str());
210 return;
211 }
212
213 // Check if we need to check if the window is obscured by parent
214 if (dropInputMode != gui::DropInputMode::OBSCURED) {
215 return;
216 }
217
218 // Check if the parent has set an alpha on the layer
219 if (parentSnapshot.color.a != 1.0_hf) {
220 snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::DROP_INPUT;
221 ALOGV("Dropping input for %s as requested by policy because alpha=%f",
222 snapshot.name.c_str(), static_cast<float>(parentSnapshot.color.a));
223 }
224
225 // Check if the parent has cropped the buffer
226 Rect bufferSize = snapshot.croppedBufferSize;
227 if (!bufferSize.isValid()) {
228 snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED;
229 return;
230 }
231
232 // Screenbounds are the layer bounds cropped by parents, transformed to screenspace.
233 // To check if the layer has been cropped, we take the buffer bounds, apply the local
234 // layer crop and apply the same set of transforms to move to screenspace. If the bounds
235 // match then the layer has not been cropped by its parents.
236 Rect bufferInScreenSpace(snapshot.geomLayerTransform.transform(bufferSize));
237 bool croppedByParent = bufferInScreenSpace != Rect{snapshot.transformedBounds};
238
239 if (croppedByParent) {
240 snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::DROP_INPUT;
241 ALOGV("Dropping input for %s as requested by policy because buffer is cropped by parent",
242 snapshot.name.c_str());
243 } else {
244 // If the layer is not obscured by its parents (by setting an alpha or crop), then only drop
245 // input if the window is obscured. This check should be done in surfaceflinger but the
246 // logic currently resides in inputflinger. So pass the if_obscured check to input to only
247 // drop input events if the window is obscured.
248 snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED;
249 }
250}
251
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000252auto getBlendMode(const LayerSnapshot& snapshot, const RequestedLayerState& requested) {
253 auto blendMode = Hwc2::IComposerClient::BlendMode::NONE;
254 if (snapshot.alpha != 1.0f || !snapshot.isContentOpaque()) {
255 blendMode = requested.premultipliedAlpha ? Hwc2::IComposerClient::BlendMode::PREMULTIPLIED
256 : Hwc2::IComposerClient::BlendMode::COVERAGE;
257 }
258 return blendMode;
259}
260
Vishnu Naircfb2d252023-01-19 04:44:02 +0000261void updateSurfaceDamage(const RequestedLayerState& requested, bool hasReadyFrame,
262 bool forceFullDamage, Region& outSurfaceDamageRegion) {
263 if (!hasReadyFrame) {
264 outSurfaceDamageRegion.clear();
265 return;
266 }
267 if (forceFullDamage) {
268 outSurfaceDamageRegion = Region::INVALID_REGION;
269 } else {
270 outSurfaceDamageRegion = requested.surfaceDamageRegion;
271 }
272}
273
Vishnu Nair80a5a702023-02-11 01:21:51 +0000274void updateVisibility(LayerSnapshot& snapshot, bool visible) {
275 snapshot.isVisible = visible;
Vishnu Naircfb2d252023-01-19 04:44:02 +0000276
277 // TODO(b/238781169) we are ignoring this compat for now, since we will have
278 // to remove any optimization based on visibility.
279
280 // For compatibility reasons we let layers which can receive input
281 // receive input before they have actually submitted a buffer. Because
282 // of this we use canReceiveInput instead of isVisible to check the
283 // policy-visibility, ignoring the buffer state. However for layers with
284 // hasInputInfo()==false we can use the real visibility state.
285 // We are just using these layers for occlusion detection in
286 // InputDispatcher, and obviously if they aren't visible they can't occlude
287 // anything.
Vishnu Nair80a5a702023-02-11 01:21:51 +0000288 const bool visibleForInput =
Vishnu Nair40d02282023-02-28 21:11:40 +0000289 snapshot.hasInputInfo() ? snapshot.canReceiveInput() : snapshot.isVisible;
Vishnu Nair80a5a702023-02-11 01:21:51 +0000290 snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visibleForInput);
Vishnu Naircfb2d252023-01-19 04:44:02 +0000291}
292
293bool needsInputInfo(const LayerSnapshot& snapshot, const RequestedLayerState& requested) {
294 if (requested.potentialCursor) {
295 return false;
296 }
297
298 if (snapshot.inputInfo.token != nullptr) {
299 return true;
300 }
301
302 if (snapshot.hasBufferOrSidebandStream()) {
303 return true;
304 }
305
306 return requested.windowInfoHandle &&
307 requested.windowInfoHandle->getInfo()->inputConfig.test(
308 gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
309}
310
Vishnu Nairc765c6c2023-02-23 00:08:01 +0000311void updateMetadata(LayerSnapshot& snapshot, const RequestedLayerState& requested,
312 const LayerSnapshotBuilder::Args& args) {
313 snapshot.metadata.clear();
314 for (const auto& [key, mandatory] : args.supportedLayerGenericMetadata) {
315 auto compatIter = args.genericLayerMetadataKeyMap.find(key);
316 if (compatIter == std::end(args.genericLayerMetadataKeyMap)) {
317 continue;
318 }
319 const uint32_t id = compatIter->second;
320 auto it = requested.metadata.mMap.find(id);
321 if (it == std::end(requested.metadata.mMap)) {
322 continue;
323 }
324
325 snapshot.metadata.emplace(key,
326 compositionengine::GenericLayerMetadataEntry{mandatory,
327 it->second});
328 }
329}
330
Vishnu Naircfb2d252023-01-19 04:44:02 +0000331void clearChanges(LayerSnapshot& snapshot) {
332 snapshot.changes.clear();
333 snapshot.contentDirty = false;
334 snapshot.hasReadyFrame = false;
335 snapshot.sidebandStreamHasFrame = false;
336 snapshot.surfaceDamage.clear();
337}
338
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000339} // namespace
340
341LayerSnapshot LayerSnapshotBuilder::getRootSnapshot() {
342 LayerSnapshot snapshot;
Vishnu Nair92990e22023-02-24 20:01:05 +0000343 snapshot.path = LayerHierarchy::TraversalPath::ROOT;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000344 snapshot.changes = ftl::Flags<RequestedLayerState::Changes>();
345 snapshot.isHiddenByPolicyFromParent = false;
346 snapshot.isHiddenByPolicyFromRelativeParent = false;
347 snapshot.parentTransform.reset();
348 snapshot.geomLayerTransform.reset();
349 snapshot.geomInverseLayerTransform.reset();
350 snapshot.geomLayerBounds = getMaxDisplayBounds({});
351 snapshot.roundedCorner = RoundedCornerState();
352 snapshot.stretchEffect = {};
353 snapshot.outputFilter.layerStack = ui::DEFAULT_LAYER_STACK;
354 snapshot.outputFilter.toInternalDisplay = false;
355 snapshot.isSecure = false;
356 snapshot.color.a = 1.0_hf;
357 snapshot.colorTransformIsIdentity = true;
358 snapshot.shadowRadius = 0.f;
359 snapshot.layerMetadata.mMap.clear();
360 snapshot.relativeLayerMetadata.mMap.clear();
361 snapshot.inputInfo.touchOcclusionMode = gui::TouchOcclusionMode::BLOCK_UNTRUSTED;
362 snapshot.dropInputMode = gui::DropInputMode::NONE;
363 snapshot.isTrustedOverlay = false;
Vishnu Naircfb2d252023-01-19 04:44:02 +0000364 snapshot.gameMode = gui::GameMode::Unsupported;
365 snapshot.frameRate = {};
366 snapshot.fixedTransformHint = ui::Transform::ROT_INVALID;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000367 return snapshot;
368}
369
370LayerSnapshotBuilder::LayerSnapshotBuilder() : mRootSnapshot(getRootSnapshot()) {}
371
372LayerSnapshotBuilder::LayerSnapshotBuilder(Args args) : LayerSnapshotBuilder() {
Vishnu Naird47bcee2023-02-24 18:08:51 +0000373 args.forceUpdate = ForceUpdateFlags::ALL;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000374 updateSnapshots(args);
375}
376
377bool LayerSnapshotBuilder::tryFastUpdate(const Args& args) {
Vishnu Naird47bcee2023-02-24 18:08:51 +0000378 if (args.forceUpdate != ForceUpdateFlags::NONE || args.displayChanges) {
Vishnu Naircfb2d252023-01-19 04:44:02 +0000379 // force update requested, or we have display changes, so skip the fast path
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000380 return false;
381 }
382
383 if (args.layerLifecycleManager.getGlobalChanges().get() == 0) {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000384 return true;
385 }
386
387 if (args.layerLifecycleManager.getGlobalChanges() != RequestedLayerState::Changes::Content) {
388 // We have changes that require us to walk the hierarchy and update child layers.
389 // No fast path for you.
390 return false;
391 }
392
393 // There are only content changes which do not require any child layer snapshots to be updated.
394 ALOGV("%s", __func__);
395 ATRACE_NAME("FastPath");
396
397 // Collect layers with changes
398 ftl::SmallMap<uint32_t, RequestedLayerState*, 10> layersWithChanges;
399 for (auto& layer : args.layerLifecycleManager.getLayers()) {
400 if (layer->changes.test(RequestedLayerState::Changes::Content)) {
401 layersWithChanges.emplace_or_replace(layer->id, layer.get());
402 }
403 }
404
405 // Walk through the snapshots, clearing previous change flags and updating the snapshots
406 // if needed.
407 for (auto& snapshot : mSnapshots) {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000408 auto it = layersWithChanges.find(snapshot->path.id);
409 if (it != layersWithChanges.end()) {
410 ALOGV("%s fast path snapshot changes = %s", __func__,
411 mRootSnapshot.changes.string().c_str());
412 LayerHierarchy::TraversalPath root = LayerHierarchy::TraversalPath::ROOT;
Vishnu Nair92990e22023-02-24 20:01:05 +0000413 updateSnapshot(*snapshot, args, *it->second, mRootSnapshot, root);
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000414 }
415 }
416 return true;
417}
418
419void LayerSnapshotBuilder::updateSnapshots(const Args& args) {
420 ATRACE_NAME("UpdateSnapshots");
Vishnu Nair3af0ec02023-02-10 04:13:48 +0000421 if (args.parentCrop) {
422 mRootSnapshot.geomLayerBounds = *args.parentCrop;
Vishnu Naird47bcee2023-02-24 18:08:51 +0000423 } else if (args.forceUpdate == ForceUpdateFlags::ALL || args.displayChanges) {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000424 mRootSnapshot.geomLayerBounds = getMaxDisplayBounds(args.displays);
425 }
426 if (args.displayChanges) {
427 mRootSnapshot.changes = RequestedLayerState::Changes::AffectsChildren |
428 RequestedLayerState::Changes::Geometry;
429 }
Vishnu Naird47bcee2023-02-24 18:08:51 +0000430 if (args.forceUpdate == ForceUpdateFlags::HIERARCHY) {
431 mRootSnapshot.changes |=
432 RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Visibility;
433 }
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000434 LayerHierarchy::TraversalPath root = LayerHierarchy::TraversalPath::ROOT;
Vishnu Naird47bcee2023-02-24 18:08:51 +0000435 if (args.root.getLayer()) {
436 // The hierarchy can have a root layer when used for screenshots otherwise, it will have
437 // multiple children.
438 LayerHierarchy::ScopedAddToTraversalPath addChildToPath(root, args.root.getLayer()->id,
439 LayerHierarchy::Variant::Attached);
440 updateSnapshotsInHierarchy(args, args.root, root, mRootSnapshot);
441 } else {
442 for (auto& [childHierarchy, variant] : args.root.mChildren) {
443 LayerHierarchy::ScopedAddToTraversalPath addChildToPath(root,
444 childHierarchy->getLayer()->id,
445 variant);
446 updateSnapshotsInHierarchy(args, *childHierarchy, root, mRootSnapshot);
447 }
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000448 }
449
Vishnu Nair29354ec2023-03-28 18:51:28 -0700450 // Update touchable region crops outside the main update pass. This is because a layer could be
451 // cropped by any other layer and it requires both snapshots to be updated.
452 updateTouchableRegionCrop(args);
453
Vishnu Nairfccd6362023-02-24 23:39:53 +0000454 const bool hasUnreachableSnapshots = sortSnapshotsByZ(args);
Vishnu Naircfb2d252023-01-19 04:44:02 +0000455 clearChanges(mRootSnapshot);
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000456
Vishnu Nair29354ec2023-03-28 18:51:28 -0700457 // Destroy unreachable snapshots for clone layers. And destroy snapshots for non-clone
458 // layers if the layer have been destroyed.
459 // TODO(b/238781169) consider making clone layer ids stable as well
460 if (!hasUnreachableSnapshots && args.layerLifecycleManager.getDestroyedLayers().empty()) {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000461 return;
462 }
463
Vishnu Nair29354ec2023-03-28 18:51:28 -0700464 std::unordered_set<uint32_t> destroyedLayerIds;
465 for (auto& destroyedLayer : args.layerLifecycleManager.getDestroyedLayers()) {
466 destroyedLayerIds.insert(destroyedLayer->id);
467 }
468
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000469 auto it = mSnapshots.begin();
470 while (it < mSnapshots.end()) {
471 auto& traversalPath = it->get()->path;
Vishnu Nair29354ec2023-03-28 18:51:28 -0700472 if (!it->get()->unreachable &&
473 destroyedLayerIds.find(traversalPath.id) == destroyedLayerIds.end()) {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000474 it++;
475 continue;
476 }
477
478 mIdToSnapshot.erase(traversalPath);
Vishnu Nair29354ec2023-03-28 18:51:28 -0700479 mNeedsTouchableRegionCrop.erase(traversalPath);
Vishnu Naircfb2d252023-01-19 04:44:02 +0000480 mSnapshots.back()->globalZ = it->get()->globalZ;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000481 std::iter_swap(it, mSnapshots.end() - 1);
482 mSnapshots.erase(mSnapshots.end() - 1);
483 }
484}
485
486void LayerSnapshotBuilder::update(const Args& args) {
Vishnu Nair92990e22023-02-24 20:01:05 +0000487 for (auto& snapshot : mSnapshots) {
488 clearChanges(*snapshot);
489 }
490
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000491 if (tryFastUpdate(args)) {
492 return;
493 }
494 updateSnapshots(args);
495}
496
Vishnu Naircfb2d252023-01-19 04:44:02 +0000497const LayerSnapshot& LayerSnapshotBuilder::updateSnapshotsInHierarchy(
498 const Args& args, const LayerHierarchy& hierarchy,
499 LayerHierarchy::TraversalPath& traversalPath, const LayerSnapshot& parentSnapshot) {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000500 const RequestedLayerState* layer = hierarchy.getLayer();
Vishnu Naircfb2d252023-01-19 04:44:02 +0000501 LayerSnapshot* snapshot = getSnapshot(traversalPath);
502 const bool newSnapshot = snapshot == nullptr;
503 if (newSnapshot) {
Vishnu Nair92990e22023-02-24 20:01:05 +0000504 snapshot = createSnapshot(traversalPath, *layer, parentSnapshot);
Vishnu Naircfb2d252023-01-19 04:44:02 +0000505 }
Vishnu Naird47bcee2023-02-24 18:08:51 +0000506 scheduler::LayerInfo::FrameRate oldFrameRate = snapshot->frameRate;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000507 if (traversalPath.isRelative()) {
508 bool parentIsRelative = traversalPath.variant == LayerHierarchy::Variant::Relative;
509 updateRelativeState(*snapshot, parentSnapshot, parentIsRelative, args);
510 } else {
511 if (traversalPath.isAttached()) {
512 resetRelativeState(*snapshot);
513 }
Vishnu Nair92990e22023-02-24 20:01:05 +0000514 updateSnapshot(*snapshot, args, *layer, parentSnapshot, traversalPath);
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000515 }
516
517 for (auto& [childHierarchy, variant] : hierarchy.mChildren) {
518 LayerHierarchy::ScopedAddToTraversalPath addChildToPath(traversalPath,
519 childHierarchy->getLayer()->id,
520 variant);
Vishnu Naircfb2d252023-01-19 04:44:02 +0000521 const LayerSnapshot& childSnapshot =
522 updateSnapshotsInHierarchy(args, *childHierarchy, traversalPath, *snapshot);
523 updateChildState(*snapshot, childSnapshot, args);
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000524 }
Vishnu Naird47bcee2023-02-24 18:08:51 +0000525
526 if (oldFrameRate == snapshot->frameRate) {
527 snapshot->changes.clear(RequestedLayerState::Changes::FrameRate);
528 }
Vishnu Naircfb2d252023-01-19 04:44:02 +0000529 return *snapshot;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000530}
531
532LayerSnapshot* LayerSnapshotBuilder::getSnapshot(uint32_t layerId) const {
533 if (layerId == UNASSIGNED_LAYER_ID) {
534 return nullptr;
535 }
536 LayerHierarchy::TraversalPath path{.id = layerId};
537 return getSnapshot(path);
538}
539
540LayerSnapshot* LayerSnapshotBuilder::getSnapshot(const LayerHierarchy::TraversalPath& id) const {
541 auto it = mIdToSnapshot.find(id);
542 return it == mIdToSnapshot.end() ? nullptr : it->second;
543}
544
Vishnu Nair92990e22023-02-24 20:01:05 +0000545LayerSnapshot* LayerSnapshotBuilder::createSnapshot(const LayerHierarchy::TraversalPath& path,
546 const RequestedLayerState& layer,
547 const LayerSnapshot& parentSnapshot) {
548 mSnapshots.emplace_back(std::make_unique<LayerSnapshot>(layer, path));
Vishnu Naircfb2d252023-01-19 04:44:02 +0000549 LayerSnapshot* snapshot = mSnapshots.back().get();
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000550 snapshot->globalZ = static_cast<size_t>(mSnapshots.size()) - 1;
Vishnu Nair92990e22023-02-24 20:01:05 +0000551 if (path.isClone() && path.variant != LayerHierarchy::Variant::Mirror) {
552 snapshot->mirrorRootPath = parentSnapshot.mirrorRootPath;
553 }
554 mIdToSnapshot[path] = snapshot;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000555 return snapshot;
556}
557
Vishnu Nairfccd6362023-02-24 23:39:53 +0000558bool LayerSnapshotBuilder::sortSnapshotsByZ(const Args& args) {
Vishnu Naird47bcee2023-02-24 18:08:51 +0000559 if (!mResortSnapshots && args.forceUpdate == ForceUpdateFlags::NONE &&
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000560 !args.layerLifecycleManager.getGlobalChanges().any(
561 RequestedLayerState::Changes::Hierarchy |
562 RequestedLayerState::Changes::Visibility)) {
563 // We are not force updating and there are no hierarchy or visibility changes. Avoid sorting
564 // the snapshots.
Vishnu Nairfccd6362023-02-24 23:39:53 +0000565 return false;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000566 }
Vishnu Naircfb2d252023-01-19 04:44:02 +0000567 mResortSnapshots = false;
568
Vishnu Nairfccd6362023-02-24 23:39:53 +0000569 for (auto& snapshot : mSnapshots) {
Vishnu Nair29354ec2023-03-28 18:51:28 -0700570 snapshot->unreachable = snapshot->path.isClone();
Vishnu Nairfccd6362023-02-24 23:39:53 +0000571 }
572
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000573 size_t globalZ = 0;
574 args.root.traverseInZOrder(
575 [this, &globalZ](const LayerHierarchy&,
576 const LayerHierarchy::TraversalPath& traversalPath) -> bool {
577 LayerSnapshot* snapshot = getSnapshot(traversalPath);
578 if (!snapshot) {
579 return false;
580 }
581
Vishnu Nairfccd6362023-02-24 23:39:53 +0000582 snapshot->unreachable = false;
Vishnu Naircfb2d252023-01-19 04:44:02 +0000583 if (snapshot->getIsVisible() || snapshot->hasInputInfo()) {
Vishnu Nair80a5a702023-02-11 01:21:51 +0000584 updateVisibility(*snapshot, snapshot->getIsVisible());
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000585 size_t oldZ = snapshot->globalZ;
586 size_t newZ = globalZ++;
587 snapshot->globalZ = newZ;
588 if (oldZ == newZ) {
589 return true;
590 }
591 mSnapshots[newZ]->globalZ = oldZ;
Vishnu Naircfb2d252023-01-19 04:44:02 +0000592 LLOGV(snapshot->sequence, "Made visible z=%zu -> %zu %s", oldZ, newZ,
593 snapshot->getDebugString().c_str());
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000594 std::iter_swap(mSnapshots.begin() + static_cast<ssize_t>(oldZ),
595 mSnapshots.begin() + static_cast<ssize_t>(newZ));
596 }
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000597 return true;
598 });
Vishnu Naircfb2d252023-01-19 04:44:02 +0000599 mNumInterestingSnapshots = (int)globalZ;
Vishnu Nairfccd6362023-02-24 23:39:53 +0000600 bool hasUnreachableSnapshots = false;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000601 while (globalZ < mSnapshots.size()) {
602 mSnapshots[globalZ]->globalZ = globalZ;
Vishnu Nair80a5a702023-02-11 01:21:51 +0000603 /* mark unreachable snapshots as explicitly invisible */
604 updateVisibility(*mSnapshots[globalZ], false);
Vishnu Nairfccd6362023-02-24 23:39:53 +0000605 if (mSnapshots[globalZ]->unreachable) {
606 hasUnreachableSnapshots = true;
607 }
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000608 globalZ++;
609 }
Vishnu Nairfccd6362023-02-24 23:39:53 +0000610 return hasUnreachableSnapshots;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000611}
612
613void LayerSnapshotBuilder::updateRelativeState(LayerSnapshot& snapshot,
614 const LayerSnapshot& parentSnapshot,
615 bool parentIsRelative, const Args& args) {
616 if (parentIsRelative) {
Vishnu Naircfb2d252023-01-19 04:44:02 +0000617 snapshot.isHiddenByPolicyFromRelativeParent =
618 parentSnapshot.isHiddenByPolicyFromParent || parentSnapshot.invalidTransform;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000619 if (args.includeMetadata) {
620 snapshot.relativeLayerMetadata = parentSnapshot.layerMetadata;
621 }
622 } else {
623 snapshot.isHiddenByPolicyFromRelativeParent =
624 parentSnapshot.isHiddenByPolicyFromRelativeParent;
625 if (args.includeMetadata) {
626 snapshot.relativeLayerMetadata = parentSnapshot.relativeLayerMetadata;
627 }
628 }
629 snapshot.isVisible = snapshot.getIsVisible();
630}
631
Vishnu Naircfb2d252023-01-19 04:44:02 +0000632void LayerSnapshotBuilder::updateChildState(LayerSnapshot& snapshot,
633 const LayerSnapshot& childSnapshot, const Args& args) {
634 if (snapshot.childState.hasValidFrameRate) {
635 return;
636 }
Vishnu Naird47bcee2023-02-24 18:08:51 +0000637 if (args.forceUpdate == ForceUpdateFlags::ALL ||
638 childSnapshot.changes.test(RequestedLayerState::Changes::FrameRate)) {
Vishnu Naircfb2d252023-01-19 04:44:02 +0000639 // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes
640 // for the same reason we are allowing touch boost for those layers. See
641 // RefreshRateSelector::rankFrameRates for details.
642 using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility;
643 const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.rate.isValid() &&
644 childSnapshot.frameRate.type == FrameRateCompatibility::Default;
645 const auto layerVotedWithNoVote =
646 childSnapshot.frameRate.type == FrameRateCompatibility::NoVote;
647 const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.rate.isValid() &&
648 childSnapshot.frameRate.type == FrameRateCompatibility::Exact;
649
650 snapshot.childState.hasValidFrameRate |= layerVotedWithDefaultCompatibility ||
651 layerVotedWithNoVote || layerVotedWithExactCompatibility;
652
653 // If we don't have a valid frame rate, but the children do, we set this
654 // layer as NoVote to allow the children to control the refresh rate
655 if (!snapshot.frameRate.rate.isValid() &&
656 snapshot.frameRate.type != FrameRateCompatibility::NoVote &&
657 snapshot.childState.hasValidFrameRate) {
658 snapshot.frameRate =
659 scheduler::LayerInfo::FrameRate(Fps(), FrameRateCompatibility::NoVote);
660 snapshot.changes |= childSnapshot.changes & RequestedLayerState::Changes::FrameRate;
661 }
662 }
663}
664
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000665void LayerSnapshotBuilder::resetRelativeState(LayerSnapshot& snapshot) {
666 snapshot.isHiddenByPolicyFromRelativeParent = false;
667 snapshot.relativeLayerMetadata.mMap.clear();
668}
669
Vishnu Nairb76d99a2023-03-19 18:22:31 -0700670uint32_t getPrimaryDisplayRotationFlags(
671 const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displays) {
672 for (auto& [_, display] : displays) {
673 if (display.isPrimary) {
674 return display.rotationFlags;
675 }
676 }
677 return 0;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000678}
679
680void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& args,
681 const RequestedLayerState& requested,
682 const LayerSnapshot& parentSnapshot,
Vishnu Nair92990e22023-02-24 20:01:05 +0000683 const LayerHierarchy::TraversalPath& path) {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000684 // Always update flags and visibility
685 ftl::Flags<RequestedLayerState::Changes> parentChanges = parentSnapshot.changes &
686 (RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Geometry |
687 RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Metadata |
Vishnu Naird47bcee2023-02-24 18:08:51 +0000688 RequestedLayerState::Changes::AffectsChildren |
689 RequestedLayerState::Changes::FrameRate);
Vishnu Nair92990e22023-02-24 20:01:05 +0000690 snapshot.changes |= parentChanges | requested.changes;
Vishnu Naircfb2d252023-01-19 04:44:02 +0000691 snapshot.isHiddenByPolicyFromParent = parentSnapshot.isHiddenByPolicyFromParent ||
Vishnu Nair3af0ec02023-02-10 04:13:48 +0000692 parentSnapshot.invalidTransform || requested.isHiddenByPolicy() ||
693 (args.excludeLayerIds.find(path.id) != args.excludeLayerIds.end());
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000694 snapshot.contentDirty = requested.what & layer_state_t::CONTENT_DIRTY;
Vishnu Naircfb2d252023-01-19 04:44:02 +0000695 // TODO(b/238781169) scope down the changes to only buffer updates.
Vishnu Naird47bcee2023-02-24 18:08:51 +0000696 snapshot.hasReadyFrame = requested.hasReadyFrame();
697 snapshot.sidebandStreamHasFrame = requested.hasSidebandStreamFrame();
Vishnu Naircfb2d252023-01-19 04:44:02 +0000698 updateSurfaceDamage(requested, snapshot.hasReadyFrame, args.forceFullDamage,
699 snapshot.surfaceDamage);
Vishnu Nair92990e22023-02-24 20:01:05 +0000700 snapshot.outputFilter.layerStack = parentSnapshot.path == LayerHierarchy::TraversalPath::ROOT
701 ? requested.layerStack
702 : parentSnapshot.outputFilter.layerStack;
Vishnu Nair80a5a702023-02-11 01:21:51 +0000703
Vishnu Nairb76d99a2023-03-19 18:22:31 -0700704 uint32_t primaryDisplayRotationFlags = getPrimaryDisplayRotationFlags(args.displays);
Vishnu Nair92990e22023-02-24 20:01:05 +0000705 const bool forceUpdate = args.forceUpdate == ForceUpdateFlags::ALL ||
706 snapshot.changes.any(RequestedLayerState::Changes::Visibility |
707 RequestedLayerState::Changes::Created);
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000708
Vishnu Naircfb2d252023-01-19 04:44:02 +0000709 // always update the buffer regardless of visibility
Vishnu Nair80a5a702023-02-11 01:21:51 +0000710 if (forceUpdate || requested.what & layer_state_t::BUFFER_CHANGES || args.displayChanges) {
Vishnu Naircfb2d252023-01-19 04:44:02 +0000711 snapshot.acquireFence =
712 (requested.externalTexture &&
713 requested.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged))
714 ? requested.bufferData->acquireFence
715 : Fence::NO_FENCE;
716 snapshot.buffer =
717 requested.externalTexture ? requested.externalTexture->getBuffer() : nullptr;
Vishnu Nairb76d99a2023-03-19 18:22:31 -0700718 snapshot.bufferSize = requested.getBufferSize(primaryDisplayRotationFlags);
Vishnu Naircfb2d252023-01-19 04:44:02 +0000719 snapshot.geomBufferSize = snapshot.bufferSize;
720 snapshot.croppedBufferSize = requested.getCroppedBufferSize(snapshot.bufferSize);
721 snapshot.dataspace = requested.dataspace;
722 snapshot.externalTexture = requested.externalTexture;
723 snapshot.frameNumber = (requested.bufferData) ? requested.bufferData->frameNumber : 0;
724 snapshot.geomBufferTransform = requested.bufferTransform;
725 snapshot.geomBufferUsesDisplayInverseTransform = requested.transformToDisplayInverse;
726 snapshot.geomContentCrop = requested.getBufferCrop();
727 snapshot.geomUsesSourceCrop = snapshot.hasBufferOrSidebandStream();
728 snapshot.hasProtectedContent = requested.externalTexture &&
729 requested.externalTexture->getUsage() & GRALLOC_USAGE_PROTECTED;
730 snapshot.isHdrY410 = requested.dataspace == ui::Dataspace::BT2020_ITU_PQ &&
731 requested.api == NATIVE_WINDOW_API_MEDIA &&
732 requested.bufferData->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102;
733 snapshot.sidebandStream = requested.sidebandStream;
734 snapshot.transparentRegionHint = requested.transparentRegion;
735 snapshot.color.rgb = requested.getColor().rgb;
Sally Qi963049b2023-03-23 14:06:21 -0700736 snapshot.currentHdrSdrRatio = requested.currentHdrSdrRatio;
737 snapshot.desiredHdrSdrRatio = requested.desiredHdrSdrRatio;
Vishnu Naircfb2d252023-01-19 04:44:02 +0000738 }
739
Vishnu Nair92990e22023-02-24 20:01:05 +0000740 if (snapshot.isHiddenByPolicyFromParent &&
741 !snapshot.changes.test(RequestedLayerState::Changes::Created)) {
Vishnu Naircfb2d252023-01-19 04:44:02 +0000742 if (forceUpdate ||
743 snapshot.changes.any(RequestedLayerState::Changes::Hierarchy |
744 RequestedLayerState::Changes::Geometry |
745 RequestedLayerState::Changes::Input)) {
746 updateInput(snapshot, requested, parentSnapshot, path, args);
747 }
748 return;
749 }
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000750
751 if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::AffectsChildren)) {
752 // If root layer, use the layer stack otherwise get the parent's layer stack.
753 snapshot.color.a = parentSnapshot.color.a * requested.color.a;
754 snapshot.alpha = snapshot.color.a;
Vishnu Nair29354ec2023-03-28 18:51:28 -0700755 snapshot.inputInfo.alpha = snapshot.color.a;
756
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000757 snapshot.isSecure =
758 parentSnapshot.isSecure || (requested.flags & layer_state_t::eLayerSecure);
759 snapshot.isTrustedOverlay = parentSnapshot.isTrustedOverlay || requested.isTrustedOverlay;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000760 snapshot.outputFilter.toInternalDisplay = parentSnapshot.outputFilter.toInternalDisplay ||
761 (requested.flags & layer_state_t::eLayerSkipScreenshot);
762 snapshot.stretchEffect = (requested.stretchEffect.hasEffect())
763 ? requested.stretchEffect
764 : parentSnapshot.stretchEffect;
765 if (!parentSnapshot.colorTransformIsIdentity) {
766 snapshot.colorTransform = parentSnapshot.colorTransform * requested.colorTransform;
767 snapshot.colorTransformIsIdentity = false;
768 } else {
769 snapshot.colorTransform = requested.colorTransform;
770 snapshot.colorTransformIsIdentity = !requested.hasColorTransform;
771 }
Vishnu Naircfb2d252023-01-19 04:44:02 +0000772 snapshot.gameMode = requested.metadata.has(gui::METADATA_GAME_MODE)
773 ? requested.gameMode
774 : parentSnapshot.gameMode;
Vishnu Naira9c43762023-01-27 19:10:25 +0000775 // Display mirrors are always placed in a VirtualDisplay so we never want to capture layers
776 // marked as skip capture
777 snapshot.handleSkipScreenshotFlag = parentSnapshot.handleSkipScreenshotFlag ||
778 (requested.layerStackToMirror != ui::INVALID_LAYER_STACK);
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000779 }
780
Vishnu Nairb76d99a2023-03-19 18:22:31 -0700781 if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::AffectsChildren) ||
782 args.displayChanges) {
783 snapshot.fixedTransformHint = requested.fixedTransformHint != ui::Transform::ROT_INVALID
784 ? requested.fixedTransformHint
785 : parentSnapshot.fixedTransformHint;
786
787 if (snapshot.fixedTransformHint != ui::Transform::ROT_INVALID) {
788 snapshot.transformHint = snapshot.fixedTransformHint;
789 } else {
790 const auto display = args.displays.get(snapshot.outputFilter.layerStack);
791 snapshot.transformHint = display.has_value()
792 ? std::make_optional<>(display->get().transformHint)
793 : std::nullopt;
794 }
795 }
796
Vishnu Naird47bcee2023-02-24 18:08:51 +0000797 if (forceUpdate ||
798 snapshot.changes.any(RequestedLayerState::Changes::FrameRate |
799 RequestedLayerState::Changes::Hierarchy)) {
800 snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() ||
801 (requested.requestedFrameRate.type ==
802 scheduler::LayerInfo::FrameRateCompatibility::NoVote))
803 ? requested.requestedFrameRate
804 : parentSnapshot.frameRate;
805 }
806
Vishnu Nairc765c6c2023-02-23 00:08:01 +0000807 if (forceUpdate || requested.what & layer_state_t::eMetadataChanged) {
808 updateMetadata(snapshot, requested, args);
809 }
810
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000811 if (forceUpdate || requested.changes.get() != 0) {
812 snapshot.compositionType = requested.getCompositionType();
813 snapshot.dimmingEnabled = requested.dimmingEnabled;
814 snapshot.layerOpaqueFlagSet =
815 (requested.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque;
Alec Mourif4af03e2023-02-11 00:25:24 +0000816 snapshot.cachingHint = requested.cachingHint;
Vishnu Nairef68d6d2023-02-28 06:18:27 +0000817 snapshot.frameRateSelectionPriority = requested.frameRateSelectionPriority;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000818 }
819
Vishnu Nair444f3952023-04-11 13:01:02 -0700820 if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::Content) ||
821 snapshot.changes.any(RequestedLayerState::Changes::AffectsChildren)) {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000822 snapshot.color.rgb = requested.getColor().rgb;
823 snapshot.isColorspaceAgnostic = requested.colorSpaceAgnostic;
Vishnu Nair80a5a702023-02-11 01:21:51 +0000824 snapshot.backgroundBlurRadius = args.supportsBlur
825 ? static_cast<int>(parentSnapshot.color.a * (float)requested.backgroundBlurRadius)
826 : 0;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000827 snapshot.blurRegions = requested.blurRegions;
Vishnu Nair80a5a702023-02-11 01:21:51 +0000828 for (auto& region : snapshot.blurRegions) {
829 region.alpha = region.alpha * snapshot.color.a;
830 }
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000831 snapshot.hdrMetadata = requested.hdrMetadata;
832 }
833
834 if (forceUpdate ||
835 snapshot.changes.any(RequestedLayerState::Changes::Hierarchy |
836 RequestedLayerState::Changes::Geometry)) {
Vishnu Nairb76d99a2023-03-19 18:22:31 -0700837 updateLayerBounds(snapshot, requested, parentSnapshot, primaryDisplayRotationFlags);
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000838 updateRoundedCorner(snapshot, requested, parentSnapshot);
839 }
840
841 if (forceUpdate ||
842 snapshot.changes.any(RequestedLayerState::Changes::Hierarchy |
843 RequestedLayerState::Changes::Geometry |
844 RequestedLayerState::Changes::Input)) {
Vishnu Naircfb2d252023-01-19 04:44:02 +0000845 updateInput(snapshot, requested, parentSnapshot, path, args);
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000846 }
847
848 // computed snapshot properties
849 updateShadows(snapshot, requested, args.globalShadowSettings);
850 if (args.includeMetadata) {
851 snapshot.layerMetadata = parentSnapshot.layerMetadata;
852 snapshot.layerMetadata.merge(requested.metadata);
853 }
854 snapshot.forceClientComposition = snapshot.isHdrY410 || snapshot.shadowSettings.length > 0 ||
855 requested.blurRegions.size() > 0 || snapshot.stretchEffect.hasEffect();
Vishnu Nairc765c6c2023-02-23 00:08:01 +0000856 snapshot.contentOpaque = snapshot.isContentOpaque();
857 snapshot.isOpaque = snapshot.contentOpaque && !snapshot.roundedCorner.hasRoundedCorners() &&
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000858 snapshot.color.a == 1.f;
859 snapshot.blendMode = getBlendMode(snapshot, requested);
Vishnu Naircfb2d252023-01-19 04:44:02 +0000860 LLOGV(snapshot.sequence,
Vishnu Nair92990e22023-02-24 20:01:05 +0000861 "%supdated %s changes:%s parent:%s requested:%s requested:%s from parent %s",
862 args.forceUpdate == ForceUpdateFlags::ALL ? "Force " : "",
863 snapshot.getDebugString().c_str(), snapshot.changes.string().c_str(),
864 parentSnapshot.changes.string().c_str(), requested.changes.string().c_str(),
865 std::to_string(requested.what).c_str(), parentSnapshot.getDebugString().c_str());
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000866}
867
868void LayerSnapshotBuilder::updateRoundedCorner(LayerSnapshot& snapshot,
869 const RequestedLayerState& requested,
870 const LayerSnapshot& parentSnapshot) {
871 snapshot.roundedCorner = RoundedCornerState();
872 RoundedCornerState parentRoundedCorner;
873 if (parentSnapshot.roundedCorner.hasRoundedCorners()) {
874 parentRoundedCorner = parentSnapshot.roundedCorner;
875 ui::Transform t = snapshot.localTransform.inverse();
876 parentRoundedCorner.cropRect = t.transform(parentRoundedCorner.cropRect);
877 parentRoundedCorner.radius.x *= t.getScaleX();
878 parentRoundedCorner.radius.y *= t.getScaleY();
879 }
880
881 FloatRect layerCropRect = snapshot.croppedBufferSize.toFloatRect();
882 const vec2 radius(requested.cornerRadius, requested.cornerRadius);
883 RoundedCornerState layerSettings(layerCropRect, radius);
884 const bool layerSettingsValid = layerSettings.hasRoundedCorners() && !layerCropRect.isEmpty();
885 const bool parentRoundedCornerValid = parentRoundedCorner.hasRoundedCorners();
886 if (layerSettingsValid && parentRoundedCornerValid) {
887 // If the parent and the layer have rounded corner settings, use the parent settings if
888 // the parent crop is entirely inside the layer crop. This has limitations and cause
889 // rendering artifacts. See b/200300845 for correct fix.
890 if (parentRoundedCorner.cropRect.left > layerCropRect.left &&
891 parentRoundedCorner.cropRect.top > layerCropRect.top &&
892 parentRoundedCorner.cropRect.right < layerCropRect.right &&
893 parentRoundedCorner.cropRect.bottom < layerCropRect.bottom) {
894 snapshot.roundedCorner = parentRoundedCorner;
895 } else {
896 snapshot.roundedCorner = layerSettings;
897 }
898 } else if (layerSettingsValid) {
899 snapshot.roundedCorner = layerSettings;
900 } else if (parentRoundedCornerValid) {
901 snapshot.roundedCorner = parentRoundedCorner;
902 }
903}
904
905void LayerSnapshotBuilder::updateLayerBounds(LayerSnapshot& snapshot,
906 const RequestedLayerState& requested,
907 const LayerSnapshot& parentSnapshot,
Vishnu Nairb76d99a2023-03-19 18:22:31 -0700908 uint32_t primaryDisplayRotationFlags) {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000909 snapshot.croppedBufferSize = requested.getCroppedBufferSize(snapshot.bufferSize);
910 snapshot.geomCrop = requested.crop;
Vishnu Nairb76d99a2023-03-19 18:22:31 -0700911 snapshot.localTransform = requested.getTransform(primaryDisplayRotationFlags);
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000912 snapshot.localTransformInverse = snapshot.localTransform.inverse();
913 snapshot.geomLayerTransform = parentSnapshot.geomLayerTransform * snapshot.localTransform;
Vishnu Naircfb2d252023-01-19 04:44:02 +0000914 const bool transformWasInvalid = snapshot.invalidTransform;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000915 snapshot.invalidTransform = !LayerSnapshot::isTransformValid(snapshot.geomLayerTransform);
916 if (snapshot.invalidTransform) {
Vishnu Naircfb2d252023-01-19 04:44:02 +0000917 auto& t = snapshot.geomLayerTransform;
918 auto& requestedT = requested.requestedTransform;
919 std::string transformDebug =
920 base::StringPrintf(" transform={%f,%f,%f,%f} requestedTransform={%f,%f,%f,%f}",
921 t.dsdx(), t.dsdy(), t.dtdx(), t.dtdy(), requestedT.dsdx(),
922 requestedT.dsdy(), requestedT.dtdx(), requestedT.dtdy());
923 std::string bufferDebug;
924 if (requested.externalTexture) {
Vishnu Nairb76d99a2023-03-19 18:22:31 -0700925 auto unRotBuffer = requested.getUnrotatedBufferSize(primaryDisplayRotationFlags);
Vishnu Naircfb2d252023-01-19 04:44:02 +0000926 auto& destFrame = requested.destinationFrame;
927 bufferDebug = base::StringPrintf(" buffer={%d,%d} displayRot=%d"
928 " destFrame={%d,%d,%d,%d} unRotBuffer={%d,%d}",
929 requested.externalTexture->getWidth(),
930 requested.externalTexture->getHeight(),
Vishnu Nairb76d99a2023-03-19 18:22:31 -0700931 primaryDisplayRotationFlags, destFrame.left,
932 destFrame.top, destFrame.right, destFrame.bottom,
Vishnu Naircfb2d252023-01-19 04:44:02 +0000933 unRotBuffer.getHeight(), unRotBuffer.getWidth());
934 }
935 ALOGW("Resetting transform for %s because it is invalid.%s%s",
936 snapshot.getDebugString().c_str(), transformDebug.c_str(), bufferDebug.c_str());
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000937 snapshot.geomLayerTransform.reset();
938 }
Vishnu Naircfb2d252023-01-19 04:44:02 +0000939 if (transformWasInvalid != snapshot.invalidTransform) {
940 // If transform is invalid, the layer will be hidden.
941 mResortSnapshots = true;
942 }
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000943 snapshot.geomInverseLayerTransform = snapshot.geomLayerTransform.inverse();
944
945 FloatRect parentBounds = parentSnapshot.geomLayerBounds;
946 parentBounds = snapshot.localTransform.inverse().transform(parentBounds);
947 snapshot.geomLayerBounds =
948 (requested.externalTexture) ? snapshot.bufferSize.toFloatRect() : parentBounds;
949 if (!requested.crop.isEmpty()) {
950 snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(requested.crop.toFloatRect());
951 }
952 snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(parentBounds);
953 snapshot.transformedBounds = snapshot.geomLayerTransform.transform(snapshot.geomLayerBounds);
Vishnu Naircfb2d252023-01-19 04:44:02 +0000954 const Rect geomLayerBoundsWithoutTransparentRegion =
955 RequestedLayerState::reduce(Rect(snapshot.geomLayerBounds),
956 requested.transparentRegion);
957 snapshot.transformedBoundsWithoutTransparentRegion =
958 snapshot.geomLayerTransform.transform(geomLayerBoundsWithoutTransparentRegion);
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000959 snapshot.parentTransform = parentSnapshot.geomLayerTransform;
960
961 // Subtract the transparent region and snap to the bounds
Vishnu Naircfb2d252023-01-19 04:44:02 +0000962 const Rect bounds =
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000963 RequestedLayerState::reduce(snapshot.croppedBufferSize, requested.transparentRegion);
Vishnu Naircfb2d252023-01-19 04:44:02 +0000964 if (requested.potentialCursor) {
965 snapshot.cursorFrame = snapshot.geomLayerTransform.transform(bounds);
966 }
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000967}
968
969void LayerSnapshotBuilder::updateShadows(LayerSnapshot& snapshot,
970 const RequestedLayerState& requested,
971 const renderengine::ShadowSettings& globalShadowSettings) {
972 snapshot.shadowRadius = requested.shadowRadius;
973 snapshot.shadowSettings.length = requested.shadowRadius;
974 if (snapshot.shadowRadius > 0.f) {
975 snapshot.shadowSettings = globalShadowSettings;
976
977 // Note: this preserves existing behavior of shadowing the entire layer and not cropping
978 // it if transparent regions are present. This may not be necessary since shadows are
979 // typically cast by layers without transparent regions.
980 snapshot.shadowSettings.boundaries = snapshot.geomLayerBounds;
981
982 // If the casting layer is translucent, we need to fill in the shadow underneath the
983 // layer. Otherwise the generated shadow will only be shown around the casting layer.
984 snapshot.shadowSettings.casterIsTranslucent =
985 !snapshot.isContentOpaque() || (snapshot.alpha < 1.0f);
986 snapshot.shadowSettings.ambientColor *= snapshot.alpha;
987 snapshot.shadowSettings.spotColor *= snapshot.alpha;
988 }
989}
990
991void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot,
992 const RequestedLayerState& requested,
993 const LayerSnapshot& parentSnapshot,
Vishnu Naircfb2d252023-01-19 04:44:02 +0000994 const LayerHierarchy::TraversalPath& path,
995 const Args& args) {
996 if (requested.windowInfoHandle) {
997 snapshot.inputInfo = *requested.windowInfoHandle->getInfo();
998 } else {
999 snapshot.inputInfo = {};
Vishnu Nair40d02282023-02-28 21:11:40 +00001000 // b/271132344 revisit this and see if we can always use the layers uid/pid
1001 snapshot.inputInfo.name = requested.name;
1002 snapshot.inputInfo.ownerUid = static_cast<int32_t>(requested.ownerUid);
1003 snapshot.inputInfo.ownerPid = requested.ownerPid;
Vishnu Naircfb2d252023-01-19 04:44:02 +00001004 }
Vishnu Nair29354ec2023-03-28 18:51:28 -07001005 snapshot.touchCropId = requested.touchCropId;
Vishnu Naircfb2d252023-01-19 04:44:02 +00001006
Vishnu Nair93b8b792023-02-27 19:40:24 +00001007 snapshot.inputInfo.id = static_cast<int32_t>(snapshot.uniqueSequence);
Vishnu Naird47bcee2023-02-24 18:08:51 +00001008 snapshot.inputInfo.displayId = static_cast<int32_t>(snapshot.outputFilter.layerStack.id);
Vishnu Nair29354ec2023-03-28 18:51:28 -07001009 updateVisibility(snapshot, snapshot.isVisible);
Vishnu Naircfb2d252023-01-19 04:44:02 +00001010 if (!needsInputInfo(snapshot, requested)) {
Vishnu Nair8fc721b2022-12-22 20:06:32 +00001011 return;
1012 }
1013
Vishnu Naircfb2d252023-01-19 04:44:02 +00001014 static frontend::DisplayInfo sDefaultInfo = {.isSecure = false};
1015 const std::optional<frontend::DisplayInfo> displayInfoOpt =
1016 args.displays.get(snapshot.outputFilter.layerStack);
1017 bool noValidDisplay = !displayInfoOpt.has_value();
1018 auto displayInfo = displayInfoOpt.value_or(sDefaultInfo);
1019
1020 if (!requested.windowInfoHandle) {
1021 snapshot.inputInfo.inputConfig = gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL;
1022 }
Vishnu Nair8fc721b2022-12-22 20:06:32 +00001023 fillInputFrameInfo(snapshot.inputInfo, displayInfo.transform, snapshot);
1024
1025 if (noValidDisplay) {
1026 // Do not let the window receive touches if it is not associated with a valid display
1027 // transform. We still allow the window to receive keys and prevent ANRs.
1028 snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::NOT_TOUCHABLE;
1029 }
1030
Vishnu Nair8fc721b2022-12-22 20:06:32 +00001031 snapshot.inputInfo.alpha = snapshot.color.a;
Vishnu Nair40d02282023-02-28 21:11:40 +00001032 snapshot.inputInfo.touchOcclusionMode = requested.hasInputInfo()
1033 ? requested.windowInfoHandle->getInfo()->touchOcclusionMode
1034 : parentSnapshot.inputInfo.touchOcclusionMode;
Vishnu Nair8fc721b2022-12-22 20:06:32 +00001035 if (requested.dropInputMode == gui::DropInputMode::ALL ||
1036 parentSnapshot.dropInputMode == gui::DropInputMode::ALL) {
1037 snapshot.dropInputMode = gui::DropInputMode::ALL;
1038 } else if (requested.dropInputMode == gui::DropInputMode::OBSCURED ||
1039 parentSnapshot.dropInputMode == gui::DropInputMode::OBSCURED) {
1040 snapshot.dropInputMode = gui::DropInputMode::OBSCURED;
1041 } else {
1042 snapshot.dropInputMode = gui::DropInputMode::NONE;
1043 }
1044
1045 handleDropInputMode(snapshot, parentSnapshot);
1046
1047 // If the window will be blacked out on a display because the display does not have the secure
1048 // flag and the layer has the secure flag set, then drop input.
1049 if (!displayInfo.isSecure && snapshot.isSecure) {
1050 snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::DROP_INPUT;
1051 }
1052
1053 auto cropLayerSnapshot = getSnapshot(requested.touchCropId);
Vishnu Nair29354ec2023-03-28 18:51:28 -07001054 if (cropLayerSnapshot) {
1055 mNeedsTouchableRegionCrop.insert(path);
1056 } else if (snapshot.inputInfo.replaceTouchableRegionWithCrop) {
1057 FloatRect inputBounds = getInputBounds(snapshot, /*fillParentBounds=*/true).first;
Vishnu Nairfed7c122023-03-18 01:54:43 +00001058 Rect inputBoundsInDisplaySpace =
Vishnu Nair29354ec2023-03-28 18:51:28 -07001059 getInputBoundsInDisplaySpace(snapshot, inputBounds, displayInfo.transform);
1060 snapshot.inputInfo.touchableRegion = Region(inputBoundsInDisplaySpace);
Vishnu Nair8fc721b2022-12-22 20:06:32 +00001061 }
1062
1063 // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
1064 // if it was set by WM for a known system overlay
1065 if (snapshot.isTrustedOverlay) {
1066 snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::TRUSTED_OVERLAY;
1067 }
1068
1069 // If the layer is a clone, we need to crop the input region to cloned root to prevent
1070 // touches from going outside the cloned area.
1071 if (path.isClone()) {
1072 snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::CLONE;
Vishnu Nair444f3952023-04-11 13:01:02 -07001073 // Cloned layers shouldn't handle watch outside since their z order is not determined by
1074 // WM or the client.
1075 snapshot.inputInfo.inputConfig.clear(gui::WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH);
1076
Vishnu Nair29354ec2023-03-28 18:51:28 -07001077 mNeedsTouchableRegionCrop.insert(path);
Vishnu Nair8fc721b2022-12-22 20:06:32 +00001078 }
1079}
1080
1081std::vector<std::unique_ptr<LayerSnapshot>>& LayerSnapshotBuilder::getSnapshots() {
1082 return mSnapshots;
1083}
1084
Vishnu Naircfb2d252023-01-19 04:44:02 +00001085void LayerSnapshotBuilder::forEachVisibleSnapshot(const ConstVisitor& visitor) const {
1086 for (int i = 0; i < mNumInterestingSnapshots; i++) {
1087 LayerSnapshot& snapshot = *mSnapshots[(size_t)i];
1088 if (!snapshot.isVisible) continue;
1089 visitor(snapshot);
1090 }
1091}
1092
Vishnu Nair3af0ec02023-02-10 04:13:48 +00001093// Visit each visible snapshot in z-order
1094void LayerSnapshotBuilder::forEachVisibleSnapshot(const ConstVisitor& visitor,
1095 const LayerHierarchy& root) const {
1096 root.traverseInZOrder(
1097 [this, visitor](const LayerHierarchy&,
1098 const LayerHierarchy::TraversalPath& traversalPath) -> bool {
1099 LayerSnapshot* snapshot = getSnapshot(traversalPath);
1100 if (snapshot && snapshot->isVisible) {
1101 visitor(*snapshot);
1102 }
1103 return true;
1104 });
1105}
1106
Vishnu Naircfb2d252023-01-19 04:44:02 +00001107void LayerSnapshotBuilder::forEachVisibleSnapshot(const Visitor& visitor) {
1108 for (int i = 0; i < mNumInterestingSnapshots; i++) {
1109 std::unique_ptr<LayerSnapshot>& snapshot = mSnapshots.at((size_t)i);
1110 if (!snapshot->isVisible) continue;
1111 visitor(snapshot);
1112 }
1113}
1114
1115void LayerSnapshotBuilder::forEachInputSnapshot(const ConstVisitor& visitor) const {
1116 for (int i = mNumInterestingSnapshots - 1; i >= 0; i--) {
1117 LayerSnapshot& snapshot = *mSnapshots[(size_t)i];
1118 if (!snapshot.hasInputInfo()) continue;
1119 visitor(snapshot);
1120 }
1121}
1122
Vishnu Nair29354ec2023-03-28 18:51:28 -07001123void LayerSnapshotBuilder::updateTouchableRegionCrop(const Args& args) {
1124 if (mNeedsTouchableRegionCrop.empty()) {
1125 return;
1126 }
1127
1128 static constexpr ftl::Flags<RequestedLayerState::Changes> AFFECTS_INPUT =
1129 RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Created |
1130 RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Geometry |
1131 RequestedLayerState::Changes::Input;
1132
1133 if (args.forceUpdate != ForceUpdateFlags::ALL &&
1134 !args.layerLifecycleManager.getGlobalChanges().any(AFFECTS_INPUT)) {
1135 return;
1136 }
1137
1138 for (auto& path : mNeedsTouchableRegionCrop) {
1139 frontend::LayerSnapshot* snapshot = getSnapshot(path);
1140 if (!snapshot) {
1141 continue;
1142 }
1143 const std::optional<frontend::DisplayInfo> displayInfoOpt =
1144 args.displays.get(snapshot->outputFilter.layerStack);
1145 static frontend::DisplayInfo sDefaultInfo = {.isSecure = false};
1146 auto displayInfo = displayInfoOpt.value_or(sDefaultInfo);
1147
1148 bool needsUpdate =
1149 args.forceUpdate == ForceUpdateFlags::ALL || snapshot->changes.any(AFFECTS_INPUT);
1150 auto cropLayerSnapshot = getSnapshot(snapshot->touchCropId);
1151 needsUpdate =
1152 needsUpdate || (cropLayerSnapshot && cropLayerSnapshot->changes.any(AFFECTS_INPUT));
1153 auto clonedRootSnapshot = path.isClone() ? getSnapshot(snapshot->mirrorRootPath) : nullptr;
1154 needsUpdate = needsUpdate ||
1155 (clonedRootSnapshot && clonedRootSnapshot->changes.any(AFFECTS_INPUT));
1156
1157 if (!needsUpdate) {
1158 continue;
1159 }
1160
1161 if (snapshot->inputInfo.replaceTouchableRegionWithCrop) {
1162 Rect inputBoundsInDisplaySpace;
1163 if (!cropLayerSnapshot) {
1164 FloatRect inputBounds = getInputBounds(*snapshot, /*fillParentBounds=*/true).first;
1165 inputBoundsInDisplaySpace =
1166 getInputBoundsInDisplaySpace(*snapshot, inputBounds, displayInfo.transform);
1167 } else {
1168 FloatRect inputBounds =
1169 getInputBounds(*cropLayerSnapshot, /*fillParentBounds=*/true).first;
1170 inputBoundsInDisplaySpace =
1171 getInputBoundsInDisplaySpace(*cropLayerSnapshot, inputBounds,
1172 displayInfo.transform);
1173 }
1174 snapshot->inputInfo.touchableRegion = Region(inputBoundsInDisplaySpace);
1175 } else if (cropLayerSnapshot) {
1176 FloatRect inputBounds =
1177 getInputBounds(*cropLayerSnapshot, /*fillParentBounds=*/true).first;
1178 Rect inputBoundsInDisplaySpace =
1179 getInputBoundsInDisplaySpace(*cropLayerSnapshot, inputBounds,
1180 displayInfo.transform);
1181 snapshot->inputInfo.touchableRegion = snapshot->inputInfo.touchableRegion.intersect(
1182 displayInfo.transform.transform(inputBoundsInDisplaySpace));
1183 }
1184
1185 // If the layer is a clone, we need to crop the input region to cloned root to prevent
1186 // touches from going outside the cloned area.
1187 if (clonedRootSnapshot) {
1188 const Rect rect =
1189 displayInfo.transform.transform(Rect{clonedRootSnapshot->transformedBounds});
1190 snapshot->inputInfo.touchableRegion =
1191 snapshot->inputInfo.touchableRegion.intersect(rect);
1192 }
1193 }
1194}
1195
Vishnu Nair8fc721b2022-12-22 20:06:32 +00001196} // namespace android::surfaceflinger::frontend