1 /*
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 "SurfaceFlinger"
21
22 #include <numeric>
23 #include <optional>
24
25 #include <ftl/small_map.h>
26 #include <gui/TraceUtils.h>
27 #include <ui/DisplayMap.h>
28 #include <ui/FloatRect.h>
29
30 #include "DisplayHardware/HWC2.h"
31 #include "DisplayHardware/Hal.h"
32 #include "LayerLog.h"
33 #include "LayerSnapshotBuilder.h"
34 #include "TimeStats/TimeStats.h"
35 #include "Tracing/TransactionTracing.h"
36
37 namespace android::surfaceflinger::frontend {
38
39 using namespace ftl::flag_operators;
40
41 namespace {
42
getMaxDisplayBounds(const DisplayInfos & displays)43 FloatRect getMaxDisplayBounds(const DisplayInfos& 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.
transformTouchableRegionSafely(const ui::Transform & t,const Region & r,const std::string & debugWindowName)66 Region 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 */
getInputTransform(const LayerSnapshot & snapshot)102 ui::Transform getInputTransform(const LayerSnapshot& snapshot) {
103 if (!snapshot.hasBufferOrSidebandStream()) {
104 return snapshot.geomLayerTransform;
105 }
106 return snapshot.parentTransform;
107 }
108
109 /**
110 * Returns the bounds used to fill the input frame and the touchable region.
111 *
112 * 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 */
getInputBounds(const LayerSnapshot & snapshot,bool fillParentBounds)116 std::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);
121 }
122
123 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{};
135 }
136
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};
148 }
149
getInputBoundsInDisplaySpace(const LayerSnapshot & snapshot,const FloatRect & insetBounds,const ui::Transform & screenToDisplay)150 Rect getInputBoundsInDisplaySpace(const LayerSnapshot& snapshot, const FloatRect& insetBounds,
151 const ui::Transform& screenToDisplay) {
152 // 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.
155
156 // 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.
163
164 // Crop the input bounds to ensure it is within the parent's bounds.
165 const FloatRect croppedInsetBoundsInLayer = snapshot.geomLayerBounds.intersect(insetBounds);
166
167 const ui::Transform layerToScreen = getInputTransform(snapshot);
168 const ui::Transform layerToDisplay = screenToDisplay * layerToScreen;
169
170 return Rect{layerToDisplay.transform(croppedInsetBoundsInLayer)};
171 }
172
fillInputFrameInfo(gui::WindowInfo & info,const ui::Transform & screenToDisplay,const LayerSnapshot & snapshot)173 void 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);
182 info.frameLeft = roundedFrameInDisplay.left;
183 info.frameTop = roundedFrameInDisplay.top;
184 info.frameRight = roundedFrameInDisplay.right;
185 info.frameBottom = roundedFrameInDisplay.bottom;
186
187 ui::Transform inputToLayer;
188 inputToLayer.set(inputBounds.left, inputBounds.top);
189 const ui::Transform layerToScreen = getInputTransform(snapshot);
190 const ui::Transform inputToDisplay = screenToDisplay * layerToScreen * inputToLayer;
191
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
handleDropInputMode(LayerSnapshot & snapshot,const LayerSnapshot & parentSnapshot)200 void 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
getBlendMode(const LayerSnapshot & snapshot,const RequestedLayerState & requested)252 auto 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
updateVisibility(LayerSnapshot & snapshot,bool visible)261 void updateVisibility(LayerSnapshot& snapshot, bool visible) {
262 snapshot.isVisible = visible;
263
264 // TODO(b/238781169) we are ignoring this compat for now, since we will have
265 // to remove any optimization based on visibility.
266
267 // For compatibility reasons we let layers which can receive input
268 // receive input before they have actually submitted a buffer. Because
269 // of this we use canReceiveInput instead of isVisible to check the
270 // policy-visibility, ignoring the buffer state. However for layers with
271 // hasInputInfo()==false we can use the real visibility state.
272 // We are just using these layers for occlusion detection in
273 // InputDispatcher, and obviously if they aren't visible they can't occlude
274 // anything.
275 const bool visibleForInput =
276 snapshot.hasInputInfo() ? snapshot.canReceiveInput() : snapshot.isVisible;
277 snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visibleForInput);
278 LLOGV(snapshot.sequence, "updating visibility %s %s", visible ? "true" : "false",
279 snapshot.getDebugString().c_str());
280 }
281
needsInputInfo(const LayerSnapshot & snapshot,const RequestedLayerState & requested)282 bool needsInputInfo(const LayerSnapshot& snapshot, const RequestedLayerState& requested) {
283 if (requested.potentialCursor) {
284 return false;
285 }
286
287 if (snapshot.inputInfo.token != nullptr) {
288 return true;
289 }
290
291 if (snapshot.hasBufferOrSidebandStream()) {
292 return true;
293 }
294
295 return requested.windowInfoHandle &&
296 requested.windowInfoHandle->getInfo()->inputConfig.test(
297 gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
298 }
299
updateMetadata(LayerSnapshot & snapshot,const RequestedLayerState & requested,const LayerSnapshotBuilder::Args & args)300 void updateMetadata(LayerSnapshot& snapshot, const RequestedLayerState& requested,
301 const LayerSnapshotBuilder::Args& args) {
302 snapshot.metadata.clear();
303 for (const auto& [key, mandatory] : args.supportedLayerGenericMetadata) {
304 auto compatIter = args.genericLayerMetadataKeyMap.find(key);
305 if (compatIter == std::end(args.genericLayerMetadataKeyMap)) {
306 continue;
307 }
308 const uint32_t id = compatIter->second;
309 auto it = requested.metadata.mMap.find(id);
310 if (it == std::end(requested.metadata.mMap)) {
311 continue;
312 }
313
314 snapshot.metadata.emplace(key,
315 compositionengine::GenericLayerMetadataEntry{mandatory,
316 it->second});
317 }
318 }
319
clearChanges(LayerSnapshot & snapshot)320 void clearChanges(LayerSnapshot& snapshot) {
321 snapshot.changes.clear();
322 snapshot.clientChanges = 0;
323 snapshot.contentDirty = false;
324 snapshot.hasReadyFrame = false;
325 snapshot.sidebandStreamHasFrame = false;
326 snapshot.surfaceDamage.clear();
327 }
328
329 // TODO (b/259407931): Remove.
getPrimaryDisplayRotationFlags(const ui::DisplayMap<ui::LayerStack,frontend::DisplayInfo> & displays)330 uint32_t getPrimaryDisplayRotationFlags(
331 const ui::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displays) {
332 for (auto& [_, display] : displays) {
333 if (display.isPrimary) {
334 return display.rotationFlags;
335 }
336 }
337 return 0;
338 }
339
340 } // namespace
341
getRootSnapshot()342 LayerSnapshot LayerSnapshotBuilder::getRootSnapshot() {
343 LayerSnapshot snapshot;
344 snapshot.path = LayerHierarchy::TraversalPath::ROOT;
345 snapshot.changes = ftl::Flags<RequestedLayerState::Changes>();
346 snapshot.clientChanges = 0;
347 snapshot.isHiddenByPolicyFromParent = false;
348 snapshot.isHiddenByPolicyFromRelativeParent = false;
349 snapshot.parentTransform.reset();
350 snapshot.geomLayerTransform.reset();
351 snapshot.geomInverseLayerTransform.reset();
352 snapshot.geomLayerBounds = getMaxDisplayBounds({});
353 snapshot.roundedCorner = RoundedCornerState();
354 snapshot.stretchEffect = {};
355 snapshot.outputFilter.layerStack = ui::DEFAULT_LAYER_STACK;
356 snapshot.outputFilter.toInternalDisplay = false;
357 snapshot.isSecure = false;
358 snapshot.color.a = 1.0_hf;
359 snapshot.colorTransformIsIdentity = true;
360 snapshot.shadowRadius = 0.f;
361 snapshot.layerMetadata.mMap.clear();
362 snapshot.relativeLayerMetadata.mMap.clear();
363 snapshot.inputInfo.touchOcclusionMode = gui::TouchOcclusionMode::BLOCK_UNTRUSTED;
364 snapshot.dropInputMode = gui::DropInputMode::NONE;
365 snapshot.isTrustedOverlay = false;
366 snapshot.gameMode = gui::GameMode::Unsupported;
367 snapshot.frameRate = {};
368 snapshot.fixedTransformHint = ui::Transform::ROT_INVALID;
369 return snapshot;
370 }
371
LayerSnapshotBuilder()372 LayerSnapshotBuilder::LayerSnapshotBuilder() : mRootSnapshot(getRootSnapshot()) {}
373
LayerSnapshotBuilder(Args args)374 LayerSnapshotBuilder::LayerSnapshotBuilder(Args args) : LayerSnapshotBuilder() {
375 args.forceUpdate = ForceUpdateFlags::ALL;
376 updateSnapshots(args);
377 }
378
tryFastUpdate(const Args & args)379 bool LayerSnapshotBuilder::tryFastUpdate(const Args& args) {
380 const bool forceUpdate = args.forceUpdate != ForceUpdateFlags::NONE;
381
382 if (args.layerLifecycleManager.getGlobalChanges().get() == 0 && !forceUpdate &&
383 !args.displayChanges) {
384 return true;
385 }
386
387 // There are only content changes which do not require any child layer snapshots to be updated.
388 ALOGV("%s", __func__);
389 ATRACE_NAME("FastPath");
390
391 uint32_t primaryDisplayRotationFlags = getPrimaryDisplayRotationFlags(args.displays);
392 if (forceUpdate || args.displayChanges) {
393 for (auto& snapshot : mSnapshots) {
394 const RequestedLayerState* requested =
395 args.layerLifecycleManager.getLayerFromId(snapshot->path.id);
396 if (!requested) continue;
397 snapshot->merge(*requested, forceUpdate, args.displayChanges, args.forceFullDamage,
398 primaryDisplayRotationFlags);
399 }
400 return false;
401 }
402
403 // Walk through all the updated requested layer states and update the corresponding snapshots.
404 for (const RequestedLayerState* requested : args.layerLifecycleManager.getChangedLayers()) {
405 auto range = mIdToSnapshots.equal_range(requested->id);
406 for (auto it = range.first; it != range.second; it++) {
407 it->second->merge(*requested, forceUpdate, args.displayChanges, args.forceFullDamage,
408 primaryDisplayRotationFlags);
409 }
410 }
411
412 if ((args.layerLifecycleManager.getGlobalChanges().get() &
413 ~(RequestedLayerState::Changes::Content | RequestedLayerState::Changes::Buffer).get()) !=
414 0) {
415 // We have changes that require us to walk the hierarchy and update child layers.
416 // No fast path for you.
417 return false;
418 }
419 return true;
420 }
421
updateSnapshots(const Args & args)422 void LayerSnapshotBuilder::updateSnapshots(const Args& args) {
423 ATRACE_NAME("UpdateSnapshots");
424 if (args.parentCrop) {
425 mRootSnapshot.geomLayerBounds = *args.parentCrop;
426 } else if (args.forceUpdate == ForceUpdateFlags::ALL || args.displayChanges) {
427 mRootSnapshot.geomLayerBounds = getMaxDisplayBounds(args.displays);
428 }
429 if (args.displayChanges) {
430 mRootSnapshot.changes = RequestedLayerState::Changes::AffectsChildren |
431 RequestedLayerState::Changes::Geometry;
432 }
433 if (args.forceUpdate == ForceUpdateFlags::HIERARCHY) {
434 mRootSnapshot.changes |=
435 RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Visibility;
436 mRootSnapshot.clientChanges |= layer_state_t::eReparent;
437 }
438
439 for (auto& snapshot : mSnapshots) {
440 if (snapshot->reachablilty == LayerSnapshot::Reachablilty::Reachable) {
441 snapshot->reachablilty = LayerSnapshot::Reachablilty::Unreachable;
442 }
443 }
444
445 LayerHierarchy::TraversalPath root = LayerHierarchy::TraversalPath::ROOT;
446 if (args.root.getLayer()) {
447 // The hierarchy can have a root layer when used for screenshots otherwise, it will have
448 // multiple children.
449 LayerHierarchy::ScopedAddToTraversalPath addChildToPath(root, args.root.getLayer()->id,
450 LayerHierarchy::Variant::Attached);
451 updateSnapshotsInHierarchy(args, args.root, root, mRootSnapshot, /*depth=*/0);
452 } else {
453 for (auto& [childHierarchy, variant] : args.root.mChildren) {
454 LayerHierarchy::ScopedAddToTraversalPath addChildToPath(root,
455 childHierarchy->getLayer()->id,
456 variant);
457 updateSnapshotsInHierarchy(args, *childHierarchy, root, mRootSnapshot, /*depth=*/0);
458 }
459 }
460
461 // Update touchable region crops outside the main update pass. This is because a layer could be
462 // cropped by any other layer and it requires both snapshots to be updated.
463 updateTouchableRegionCrop(args);
464
465 const bool hasUnreachableSnapshots = sortSnapshotsByZ(args);
466 clearChanges(mRootSnapshot);
467
468 // Destroy unreachable snapshots for clone layers. And destroy snapshots for non-clone
469 // layers if the layer have been destroyed.
470 // TODO(b/238781169) consider making clone layer ids stable as well
471 if (!hasUnreachableSnapshots && args.layerLifecycleManager.getDestroyedLayers().empty()) {
472 return;
473 }
474
475 std::unordered_set<uint32_t> destroyedLayerIds;
476 for (auto& destroyedLayer : args.layerLifecycleManager.getDestroyedLayers()) {
477 destroyedLayerIds.insert(destroyedLayer->id);
478 }
479
480 auto it = mSnapshots.begin();
481 while (it < mSnapshots.end()) {
482 auto& traversalPath = it->get()->path;
483 const bool unreachable =
484 it->get()->reachablilty == LayerSnapshot::Reachablilty::Unreachable;
485 const bool isClone = traversalPath.isClone();
486 const bool layerIsDestroyed =
487 destroyedLayerIds.find(traversalPath.id) != destroyedLayerIds.end();
488 const bool destroySnapshot = (unreachable && isClone) || layerIsDestroyed;
489
490 if (!destroySnapshot) {
491 it++;
492 continue;
493 }
494
495 mPathToSnapshot.erase(traversalPath);
496
497 auto range = mIdToSnapshots.equal_range(traversalPath.id);
498 auto matchingSnapshot =
499 std::find_if(range.first, range.second, [&traversalPath](auto& snapshotWithId) {
500 return snapshotWithId.second->path == traversalPath;
501 });
502 mIdToSnapshots.erase(matchingSnapshot);
503 mNeedsTouchableRegionCrop.erase(traversalPath);
504 mSnapshots.back()->globalZ = it->get()->globalZ;
505 std::iter_swap(it, mSnapshots.end() - 1);
506 mSnapshots.erase(mSnapshots.end() - 1);
507 }
508 }
509
update(const Args & args)510 void LayerSnapshotBuilder::update(const Args& args) {
511 for (auto& snapshot : mSnapshots) {
512 clearChanges(*snapshot);
513 }
514
515 if (tryFastUpdate(args)) {
516 return;
517 }
518 updateSnapshots(args);
519 }
520
updateSnapshotsInHierarchy(const Args & args,const LayerHierarchy & hierarchy,LayerHierarchy::TraversalPath & traversalPath,const LayerSnapshot & parentSnapshot,int depth)521 const LayerSnapshot& LayerSnapshotBuilder::updateSnapshotsInHierarchy(
522 const Args& args, const LayerHierarchy& hierarchy,
523 LayerHierarchy::TraversalPath& traversalPath, const LayerSnapshot& parentSnapshot,
524 int depth) {
525 if (depth > 50) {
526 TransactionTraceWriter::getInstance().invoke("layer_builder_stack_overflow_",
527 /*overwrite=*/false);
528 LOG_ALWAYS_FATAL("Cycle detected in LayerSnapshotBuilder. See "
529 "builder_stack_overflow_transactions.winscope");
530 }
531
532 const RequestedLayerState* layer = hierarchy.getLayer();
533 LayerSnapshot* snapshot = getSnapshot(traversalPath);
534 const bool newSnapshot = snapshot == nullptr;
535 uint32_t primaryDisplayRotationFlags = getPrimaryDisplayRotationFlags(args.displays);
536 if (newSnapshot) {
537 snapshot = createSnapshot(traversalPath, *layer, parentSnapshot);
538 snapshot->merge(*layer, /*forceUpdate=*/true, /*displayChanges=*/true, args.forceFullDamage,
539 primaryDisplayRotationFlags);
540 snapshot->changes |= RequestedLayerState::Changes::Created;
541 }
542 scheduler::LayerInfo::FrameRate oldFrameRate = snapshot->frameRate;
543 if (traversalPath.isRelative()) {
544 bool parentIsRelative = traversalPath.variant == LayerHierarchy::Variant::Relative;
545 updateRelativeState(*snapshot, parentSnapshot, parentIsRelative, args);
546 } else {
547 if (traversalPath.isAttached()) {
548 resetRelativeState(*snapshot);
549 }
550 updateSnapshot(*snapshot, args, *layer, parentSnapshot, traversalPath);
551 }
552
553 for (auto& [childHierarchy, variant] : hierarchy.mChildren) {
554 LayerHierarchy::ScopedAddToTraversalPath addChildToPath(traversalPath,
555 childHierarchy->getLayer()->id,
556 variant);
557 const LayerSnapshot& childSnapshot =
558 updateSnapshotsInHierarchy(args, *childHierarchy, traversalPath, *snapshot,
559 depth + 1);
560 updateChildState(*snapshot, childSnapshot, args);
561 }
562
563 if (oldFrameRate == snapshot->frameRate) {
564 snapshot->changes.clear(RequestedLayerState::Changes::FrameRate);
565 }
566 return *snapshot;
567 }
568
getSnapshot(uint32_t layerId) const569 LayerSnapshot* LayerSnapshotBuilder::getSnapshot(uint32_t layerId) const {
570 if (layerId == UNASSIGNED_LAYER_ID) {
571 return nullptr;
572 }
573 LayerHierarchy::TraversalPath path{.id = layerId};
574 return getSnapshot(path);
575 }
576
getSnapshot(const LayerHierarchy::TraversalPath & id) const577 LayerSnapshot* LayerSnapshotBuilder::getSnapshot(const LayerHierarchy::TraversalPath& id) const {
578 auto it = mPathToSnapshot.find(id);
579 return it == mPathToSnapshot.end() ? nullptr : it->second;
580 }
581
createSnapshot(const LayerHierarchy::TraversalPath & path,const RequestedLayerState & layer,const LayerSnapshot & parentSnapshot)582 LayerSnapshot* LayerSnapshotBuilder::createSnapshot(const LayerHierarchy::TraversalPath& path,
583 const RequestedLayerState& layer,
584 const LayerSnapshot& parentSnapshot) {
585 mSnapshots.emplace_back(std::make_unique<LayerSnapshot>(layer, path));
586 LayerSnapshot* snapshot = mSnapshots.back().get();
587 snapshot->globalZ = static_cast<size_t>(mSnapshots.size()) - 1;
588 if (path.isClone() && path.variant != LayerHierarchy::Variant::Mirror) {
589 snapshot->mirrorRootPath = parentSnapshot.mirrorRootPath;
590 }
591 mPathToSnapshot[path] = snapshot;
592
593 mIdToSnapshots.emplace(path.id, snapshot);
594 return snapshot;
595 }
596
sortSnapshotsByZ(const Args & args)597 bool LayerSnapshotBuilder::sortSnapshotsByZ(const Args& args) {
598 if (!mResortSnapshots && args.forceUpdate == ForceUpdateFlags::NONE &&
599 !args.layerLifecycleManager.getGlobalChanges().any(
600 RequestedLayerState::Changes::Hierarchy |
601 RequestedLayerState::Changes::Visibility)) {
602 // We are not force updating and there are no hierarchy or visibility changes. Avoid sorting
603 // the snapshots.
604 return false;
605 }
606 mResortSnapshots = false;
607
608 size_t globalZ = 0;
609 args.root.traverseInZOrder(
610 [this, &globalZ](const LayerHierarchy&,
611 const LayerHierarchy::TraversalPath& traversalPath) -> bool {
612 LayerSnapshot* snapshot = getSnapshot(traversalPath);
613 if (!snapshot) {
614 return true;
615 }
616
617 if (snapshot->getIsVisible() || snapshot->hasInputInfo()) {
618 updateVisibility(*snapshot, snapshot->getIsVisible());
619 size_t oldZ = snapshot->globalZ;
620 size_t newZ = globalZ++;
621 snapshot->globalZ = newZ;
622 if (oldZ == newZ) {
623 return true;
624 }
625 mSnapshots[newZ]->globalZ = oldZ;
626 LLOGV(snapshot->sequence, "Made visible z=%zu -> %zu %s", oldZ, newZ,
627 snapshot->getDebugString().c_str());
628 std::iter_swap(mSnapshots.begin() + static_cast<ssize_t>(oldZ),
629 mSnapshots.begin() + static_cast<ssize_t>(newZ));
630 }
631 return true;
632 });
633 mNumInterestingSnapshots = (int)globalZ;
634 bool hasUnreachableSnapshots = false;
635 while (globalZ < mSnapshots.size()) {
636 mSnapshots[globalZ]->globalZ = globalZ;
637 /* mark unreachable snapshots as explicitly invisible */
638 updateVisibility(*mSnapshots[globalZ], false);
639 if (mSnapshots[globalZ]->reachablilty == LayerSnapshot::Reachablilty::Unreachable) {
640 hasUnreachableSnapshots = true;
641 }
642 globalZ++;
643 }
644 return hasUnreachableSnapshots;
645 }
646
updateRelativeState(LayerSnapshot & snapshot,const LayerSnapshot & parentSnapshot,bool parentIsRelative,const Args & args)647 void LayerSnapshotBuilder::updateRelativeState(LayerSnapshot& snapshot,
648 const LayerSnapshot& parentSnapshot,
649 bool parentIsRelative, const Args& args) {
650 if (parentIsRelative) {
651 snapshot.isHiddenByPolicyFromRelativeParent =
652 parentSnapshot.isHiddenByPolicyFromParent || parentSnapshot.invalidTransform;
653 if (args.includeMetadata) {
654 snapshot.relativeLayerMetadata = parentSnapshot.layerMetadata;
655 }
656 } else {
657 snapshot.isHiddenByPolicyFromRelativeParent =
658 parentSnapshot.isHiddenByPolicyFromRelativeParent;
659 if (args.includeMetadata) {
660 snapshot.relativeLayerMetadata = parentSnapshot.relativeLayerMetadata;
661 }
662 }
663 if (snapshot.reachablilty == LayerSnapshot::Reachablilty::Unreachable) {
664 snapshot.reachablilty = LayerSnapshot::Reachablilty::ReachableByRelativeParent;
665 }
666 }
667
updateChildState(LayerSnapshot & snapshot,const LayerSnapshot & childSnapshot,const Args & args)668 void LayerSnapshotBuilder::updateChildState(LayerSnapshot& snapshot,
669 const LayerSnapshot& childSnapshot, const Args& args) {
670 if (snapshot.childState.hasValidFrameRate) {
671 return;
672 }
673 if (args.forceUpdate == ForceUpdateFlags::ALL ||
674 childSnapshot.changes.test(RequestedLayerState::Changes::FrameRate)) {
675 // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes
676 // for the same reason we are allowing touch boost for those layers. See
677 // RefreshRateSelector::rankFrameRates for details.
678 using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility;
679 const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.rate.isValid() &&
680 childSnapshot.frameRate.type == FrameRateCompatibility::Default;
681 const auto layerVotedWithNoVote =
682 childSnapshot.frameRate.type == FrameRateCompatibility::NoVote;
683 const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.rate.isValid() &&
684 childSnapshot.frameRate.type == FrameRateCompatibility::Exact;
685
686 snapshot.childState.hasValidFrameRate |= layerVotedWithDefaultCompatibility ||
687 layerVotedWithNoVote || layerVotedWithExactCompatibility;
688
689 // If we don't have a valid frame rate, but the children do, we set this
690 // layer as NoVote to allow the children to control the refresh rate
691 if (!snapshot.frameRate.rate.isValid() &&
692 snapshot.frameRate.type != FrameRateCompatibility::NoVote &&
693 snapshot.childState.hasValidFrameRate) {
694 snapshot.frameRate =
695 scheduler::LayerInfo::FrameRate(Fps(), FrameRateCompatibility::NoVote);
696 snapshot.changes |= childSnapshot.changes & RequestedLayerState::Changes::FrameRate;
697 }
698 }
699 }
700
resetRelativeState(LayerSnapshot & snapshot)701 void LayerSnapshotBuilder::resetRelativeState(LayerSnapshot& snapshot) {
702 snapshot.isHiddenByPolicyFromRelativeParent = false;
703 snapshot.relativeLayerMetadata.mMap.clear();
704 }
705
updateSnapshot(LayerSnapshot & snapshot,const Args & args,const RequestedLayerState & requested,const LayerSnapshot & parentSnapshot,const LayerHierarchy::TraversalPath & path)706 void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& args,
707 const RequestedLayerState& requested,
708 const LayerSnapshot& parentSnapshot,
709 const LayerHierarchy::TraversalPath& path) {
710 // Always update flags and visibility
711 ftl::Flags<RequestedLayerState::Changes> parentChanges = parentSnapshot.changes &
712 (RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Geometry |
713 RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Metadata |
714 RequestedLayerState::Changes::AffectsChildren |
715 RequestedLayerState::Changes::FrameRate | RequestedLayerState::Changes::GameMode);
716 snapshot.changes |= parentChanges;
717 if (args.displayChanges) snapshot.changes |= RequestedLayerState::Changes::Geometry;
718 snapshot.reachablilty = LayerSnapshot::Reachablilty::Reachable;
719 snapshot.clientChanges |= (parentSnapshot.clientChanges & layer_state_t::AFFECTS_CHILDREN);
720 snapshot.isHiddenByPolicyFromParent = parentSnapshot.isHiddenByPolicyFromParent ||
721 parentSnapshot.invalidTransform || requested.isHiddenByPolicy() ||
722 (args.excludeLayerIds.find(path.id) != args.excludeLayerIds.end());
723
724 const bool forceUpdate = args.forceUpdate == ForceUpdateFlags::ALL ||
725 snapshot.clientChanges & layer_state_t::eReparent ||
726 snapshot.changes.any(RequestedLayerState::Changes::Visibility |
727 RequestedLayerState::Changes::Created);
728
729 if (forceUpdate || snapshot.clientChanges & layer_state_t::eLayerStackChanged) {
730 // If root layer, use the layer stack otherwise get the parent's layer stack.
731 snapshot.outputFilter.layerStack =
732 parentSnapshot.path == LayerHierarchy::TraversalPath::ROOT
733 ? requested.layerStack
734 : parentSnapshot.outputFilter.layerStack;
735 }
736
737 if (snapshot.isHiddenByPolicyFromParent &&
738 !snapshot.changes.test(RequestedLayerState::Changes::Created)) {
739 if (forceUpdate ||
740 snapshot.changes.any(RequestedLayerState::Changes::Geometry |
741 RequestedLayerState::Changes::Input)) {
742 updateInput(snapshot, requested, parentSnapshot, path, args);
743 }
744 return;
745 }
746
747 if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::Mirror)) {
748 // Display mirrors are always placed in a VirtualDisplay so we never want to capture layers
749 // marked as skip capture
750 snapshot.handleSkipScreenshotFlag = parentSnapshot.handleSkipScreenshotFlag ||
751 (requested.layerStackToMirror != ui::INVALID_LAYER_STACK);
752 }
753
754 if (forceUpdate || snapshot.clientChanges & layer_state_t::eAlphaChanged) {
755 snapshot.color.a = parentSnapshot.color.a * requested.color.a;
756 snapshot.alpha = snapshot.color.a;
757 snapshot.inputInfo.alpha = snapshot.color.a;
758 }
759
760 if (forceUpdate || snapshot.clientChanges & layer_state_t::eFlagsChanged) {
761 snapshot.isSecure =
762 parentSnapshot.isSecure || (requested.flags & layer_state_t::eLayerSecure);
763 snapshot.outputFilter.toInternalDisplay = parentSnapshot.outputFilter.toInternalDisplay ||
764 (requested.flags & layer_state_t::eLayerSkipScreenshot);
765 }
766
767 if (forceUpdate || snapshot.clientChanges & layer_state_t::eTrustedOverlayChanged) {
768 snapshot.isTrustedOverlay = parentSnapshot.isTrustedOverlay || requested.isTrustedOverlay;
769 }
770
771 if (forceUpdate || snapshot.clientChanges & layer_state_t::eStretchChanged) {
772 snapshot.stretchEffect = (requested.stretchEffect.hasEffect())
773 ? requested.stretchEffect
774 : parentSnapshot.stretchEffect;
775 }
776
777 if (forceUpdate || snapshot.clientChanges & layer_state_t::eColorTransformChanged) {
778 if (!parentSnapshot.colorTransformIsIdentity) {
779 snapshot.colorTransform = parentSnapshot.colorTransform * requested.colorTransform;
780 snapshot.colorTransformIsIdentity = false;
781 } else {
782 snapshot.colorTransform = requested.colorTransform;
783 snapshot.colorTransformIsIdentity = !requested.hasColorTransform;
784 }
785 }
786
787 if (forceUpdate || snapshot.changes.test(RequestedLayerState::Changes::GameMode)) {
788 snapshot.gameMode = requested.metadata.has(gui::METADATA_GAME_MODE)
789 ? requested.gameMode
790 : parentSnapshot.gameMode;
791 updateMetadata(snapshot, requested, args);
792 if (args.includeMetadata) {
793 snapshot.layerMetadata = parentSnapshot.layerMetadata;
794 snapshot.layerMetadata.merge(requested.metadata);
795 }
796 }
797
798 if (forceUpdate || snapshot.clientChanges & layer_state_t::eFixedTransformHintChanged ||
799 args.displayChanges) {
800 snapshot.fixedTransformHint = requested.fixedTransformHint != ui::Transform::ROT_INVALID
801 ? requested.fixedTransformHint
802 : parentSnapshot.fixedTransformHint;
803
804 if (snapshot.fixedTransformHint != ui::Transform::ROT_INVALID) {
805 snapshot.transformHint = snapshot.fixedTransformHint;
806 } else {
807 const auto display = args.displays.get(snapshot.outputFilter.layerStack);
808 snapshot.transformHint = display.has_value()
809 ? std::make_optional<>(display->get().transformHint)
810 : std::nullopt;
811 }
812 }
813
814 if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::FrameRate)) {
815 snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() ||
816 (requested.requestedFrameRate.type ==
817 scheduler::LayerInfo::FrameRateCompatibility::NoVote))
818 ? requested.requestedFrameRate
819 : parentSnapshot.frameRate;
820 }
821
822 if (forceUpdate ||
823 snapshot.clientChanges &
824 (layer_state_t::eBackgroundBlurRadiusChanged | layer_state_t::eBlurRegionsChanged |
825 layer_state_t::eAlphaChanged)) {
826 snapshot.backgroundBlurRadius = args.supportsBlur
827 ? static_cast<int>(parentSnapshot.color.a * (float)requested.backgroundBlurRadius)
828 : 0;
829 snapshot.blurRegions = requested.blurRegions;
830 for (auto& region : snapshot.blurRegions) {
831 region.alpha = region.alpha * snapshot.color.a;
832 }
833 }
834
835 if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::Geometry)) {
836 uint32_t primaryDisplayRotationFlags = getPrimaryDisplayRotationFlags(args.displays);
837 updateLayerBounds(snapshot, requested, parentSnapshot, primaryDisplayRotationFlags);
838 }
839
840 if (forceUpdate || snapshot.clientChanges & layer_state_t::eCornerRadiusChanged ||
841 snapshot.changes.any(RequestedLayerState::Changes::Geometry)) {
842 updateRoundedCorner(snapshot, requested, parentSnapshot);
843 }
844
845 if (forceUpdate || snapshot.clientChanges & layer_state_t::eShadowRadiusChanged ||
846 snapshot.changes.any(RequestedLayerState::Changes::Geometry)) {
847 updateShadows(snapshot, requested, args.globalShadowSettings);
848 }
849
850 if (forceUpdate ||
851 snapshot.changes.any(RequestedLayerState::Changes::Geometry |
852 RequestedLayerState::Changes::Input)) {
853 updateInput(snapshot, requested, parentSnapshot, path, args);
854 }
855
856 // computed snapshot properties
857 snapshot.forceClientComposition = snapshot.isHdrY410 || snapshot.shadowSettings.length > 0 ||
858 requested.blurRegions.size() > 0 || snapshot.stretchEffect.hasEffect();
859 snapshot.contentOpaque = snapshot.isContentOpaque();
860 snapshot.isOpaque = snapshot.contentOpaque && !snapshot.roundedCorner.hasRoundedCorners() &&
861 snapshot.color.a == 1.f;
862 snapshot.blendMode = getBlendMode(snapshot, requested);
863 LLOGV(snapshot.sequence,
864 "%supdated %s changes:%s parent:%s requested:%s requested:%s from parent %s",
865 args.forceUpdate == ForceUpdateFlags::ALL ? "Force " : "",
866 snapshot.getDebugString().c_str(), snapshot.changes.string().c_str(),
867 parentSnapshot.changes.string().c_str(), requested.changes.string().c_str(),
868 std::to_string(requested.what).c_str(), parentSnapshot.getDebugString().c_str());
869 }
870
updateRoundedCorner(LayerSnapshot & snapshot,const RequestedLayerState & requested,const LayerSnapshot & parentSnapshot)871 void LayerSnapshotBuilder::updateRoundedCorner(LayerSnapshot& snapshot,
872 const RequestedLayerState& requested,
873 const LayerSnapshot& parentSnapshot) {
874 snapshot.roundedCorner = RoundedCornerState();
875 RoundedCornerState parentRoundedCorner;
876 if (parentSnapshot.roundedCorner.hasRoundedCorners()) {
877 parentRoundedCorner = parentSnapshot.roundedCorner;
878 ui::Transform t = snapshot.localTransform.inverse();
879 parentRoundedCorner.cropRect = t.transform(parentRoundedCorner.cropRect);
880 parentRoundedCorner.radius.x *= t.getScaleX();
881 parentRoundedCorner.radius.y *= t.getScaleY();
882 }
883
884 FloatRect layerCropRect = snapshot.croppedBufferSize.toFloatRect();
885 const vec2 radius(requested.cornerRadius, requested.cornerRadius);
886 RoundedCornerState layerSettings(layerCropRect, radius);
887 const bool layerSettingsValid = layerSettings.hasRoundedCorners() && !layerCropRect.isEmpty();
888 const bool parentRoundedCornerValid = parentRoundedCorner.hasRoundedCorners();
889 if (layerSettingsValid && parentRoundedCornerValid) {
890 // If the parent and the layer have rounded corner settings, use the parent settings if
891 // the parent crop is entirely inside the layer crop. This has limitations and cause
892 // rendering artifacts. See b/200300845 for correct fix.
893 if (parentRoundedCorner.cropRect.left > layerCropRect.left &&
894 parentRoundedCorner.cropRect.top > layerCropRect.top &&
895 parentRoundedCorner.cropRect.right < layerCropRect.right &&
896 parentRoundedCorner.cropRect.bottom < layerCropRect.bottom) {
897 snapshot.roundedCorner = parentRoundedCorner;
898 } else {
899 snapshot.roundedCorner = layerSettings;
900 }
901 } else if (layerSettingsValid) {
902 snapshot.roundedCorner = layerSettings;
903 } else if (parentRoundedCornerValid) {
904 snapshot.roundedCorner = parentRoundedCorner;
905 }
906 }
907
updateLayerBounds(LayerSnapshot & snapshot,const RequestedLayerState & requested,const LayerSnapshot & parentSnapshot,uint32_t primaryDisplayRotationFlags)908 void LayerSnapshotBuilder::updateLayerBounds(LayerSnapshot& snapshot,
909 const RequestedLayerState& requested,
910 const LayerSnapshot& parentSnapshot,
911 uint32_t primaryDisplayRotationFlags) {
912 snapshot.geomLayerTransform = parentSnapshot.geomLayerTransform * snapshot.localTransform;
913 const bool transformWasInvalid = snapshot.invalidTransform;
914 snapshot.invalidTransform = !LayerSnapshot::isTransformValid(snapshot.geomLayerTransform);
915 if (snapshot.invalidTransform) {
916 auto& t = snapshot.geomLayerTransform;
917 auto& requestedT = requested.requestedTransform;
918 std::string transformDebug =
919 base::StringPrintf(" transform={%f,%f,%f,%f} requestedTransform={%f,%f,%f,%f}",
920 t.dsdx(), t.dsdy(), t.dtdx(), t.dtdy(), requestedT.dsdx(),
921 requestedT.dsdy(), requestedT.dtdx(), requestedT.dtdy());
922 std::string bufferDebug;
923 if (requested.externalTexture) {
924 auto unRotBuffer = requested.getUnrotatedBufferSize(primaryDisplayRotationFlags);
925 auto& destFrame = requested.destinationFrame;
926 bufferDebug = base::StringPrintf(" buffer={%d,%d} displayRot=%d"
927 " destFrame={%d,%d,%d,%d} unRotBuffer={%d,%d}",
928 requested.externalTexture->getWidth(),
929 requested.externalTexture->getHeight(),
930 primaryDisplayRotationFlags, destFrame.left,
931 destFrame.top, destFrame.right, destFrame.bottom,
932 unRotBuffer.getHeight(), unRotBuffer.getWidth());
933 }
934 ALOGW("Resetting transform for %s because it is invalid.%s%s",
935 snapshot.getDebugString().c_str(), transformDebug.c_str(), bufferDebug.c_str());
936 snapshot.geomLayerTransform.reset();
937 }
938 if (transformWasInvalid != snapshot.invalidTransform) {
939 // If transform is invalid, the layer will be hidden.
940 mResortSnapshots = true;
941 }
942 snapshot.geomInverseLayerTransform = snapshot.geomLayerTransform.inverse();
943
944 FloatRect parentBounds = parentSnapshot.geomLayerBounds;
945 parentBounds = snapshot.localTransform.inverse().transform(parentBounds);
946 snapshot.geomLayerBounds =
947 (requested.externalTexture) ? snapshot.bufferSize.toFloatRect() : parentBounds;
948 if (!requested.crop.isEmpty()) {
949 snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(requested.crop.toFloatRect());
950 }
951 snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(parentBounds);
952 snapshot.transformedBounds = snapshot.geomLayerTransform.transform(snapshot.geomLayerBounds);
953 const Rect geomLayerBoundsWithoutTransparentRegion =
954 RequestedLayerState::reduce(Rect(snapshot.geomLayerBounds),
955 requested.transparentRegion);
956 snapshot.transformedBoundsWithoutTransparentRegion =
957 snapshot.geomLayerTransform.transform(geomLayerBoundsWithoutTransparentRegion);
958 snapshot.parentTransform = parentSnapshot.geomLayerTransform;
959
960 // Subtract the transparent region and snap to the bounds
961 const Rect bounds =
962 RequestedLayerState::reduce(snapshot.croppedBufferSize, requested.transparentRegion);
963 if (requested.potentialCursor) {
964 snapshot.cursorFrame = snapshot.geomLayerTransform.transform(bounds);
965 }
966 }
967
updateShadows(LayerSnapshot & snapshot,const RequestedLayerState &,const renderengine::ShadowSettings & globalShadowSettings)968 void LayerSnapshotBuilder::updateShadows(LayerSnapshot& snapshot, const RequestedLayerState&,
969 const renderengine::ShadowSettings& globalShadowSettings) {
970 if (snapshot.shadowRadius > 0.f) {
971 snapshot.shadowSettings = globalShadowSettings;
972
973 // Note: this preserves existing behavior of shadowing the entire layer and not cropping
974 // it if transparent regions are present. This may not be necessary since shadows are
975 // typically cast by layers without transparent regions.
976 snapshot.shadowSettings.boundaries = snapshot.geomLayerBounds;
977
978 // If the casting layer is translucent, we need to fill in the shadow underneath the
979 // layer. Otherwise the generated shadow will only be shown around the casting layer.
980 snapshot.shadowSettings.casterIsTranslucent =
981 !snapshot.isContentOpaque() || (snapshot.alpha < 1.0f);
982 snapshot.shadowSettings.ambientColor *= snapshot.alpha;
983 snapshot.shadowSettings.spotColor *= snapshot.alpha;
984 }
985 }
986
updateInput(LayerSnapshot & snapshot,const RequestedLayerState & requested,const LayerSnapshot & parentSnapshot,const LayerHierarchy::TraversalPath & path,const Args & args)987 void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot,
988 const RequestedLayerState& requested,
989 const LayerSnapshot& parentSnapshot,
990 const LayerHierarchy::TraversalPath& path,
991 const Args& args) {
992 if (requested.windowInfoHandle) {
993 snapshot.inputInfo = *requested.windowInfoHandle->getInfo();
994 } else {
995 snapshot.inputInfo = {};
996 // b/271132344 revisit this and see if we can always use the layers uid/pid
997 snapshot.inputInfo.name = requested.name;
998 snapshot.inputInfo.ownerUid = gui::Uid{requested.ownerUid};
999 snapshot.inputInfo.ownerPid = gui::Pid{requested.ownerPid};
1000 }
1001 snapshot.touchCropId = requested.touchCropId;
1002
1003 snapshot.inputInfo.id = static_cast<int32_t>(snapshot.uniqueSequence);
1004 snapshot.inputInfo.displayId = static_cast<int32_t>(snapshot.outputFilter.layerStack.id);
1005 updateVisibility(snapshot, snapshot.isVisible);
1006 if (!needsInputInfo(snapshot, requested)) {
1007 return;
1008 }
1009
1010 static frontend::DisplayInfo sDefaultInfo = {.isSecure = false};
1011 const std::optional<frontend::DisplayInfo> displayInfoOpt =
1012 args.displays.get(snapshot.outputFilter.layerStack);
1013 bool noValidDisplay = !displayInfoOpt.has_value();
1014 auto displayInfo = displayInfoOpt.value_or(sDefaultInfo);
1015
1016 if (!requested.windowInfoHandle) {
1017 snapshot.inputInfo.inputConfig = gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL;
1018 }
1019 fillInputFrameInfo(snapshot.inputInfo, displayInfo.transform, snapshot);
1020
1021 if (noValidDisplay) {
1022 // Do not let the window receive touches if it is not associated with a valid display
1023 // transform. We still allow the window to receive keys and prevent ANRs.
1024 snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::NOT_TOUCHABLE;
1025 }
1026
1027 snapshot.inputInfo.alpha = snapshot.color.a;
1028 snapshot.inputInfo.touchOcclusionMode = requested.hasInputInfo()
1029 ? requested.windowInfoHandle->getInfo()->touchOcclusionMode
1030 : parentSnapshot.inputInfo.touchOcclusionMode;
1031 if (requested.dropInputMode == gui::DropInputMode::ALL ||
1032 parentSnapshot.dropInputMode == gui::DropInputMode::ALL) {
1033 snapshot.dropInputMode = gui::DropInputMode::ALL;
1034 } else if (requested.dropInputMode == gui::DropInputMode::OBSCURED ||
1035 parentSnapshot.dropInputMode == gui::DropInputMode::OBSCURED) {
1036 snapshot.dropInputMode = gui::DropInputMode::OBSCURED;
1037 } else {
1038 snapshot.dropInputMode = gui::DropInputMode::NONE;
1039 }
1040
1041 handleDropInputMode(snapshot, parentSnapshot);
1042
1043 // If the window will be blacked out on a display because the display does not have the secure
1044 // flag and the layer has the secure flag set, then drop input.
1045 if (!displayInfo.isSecure && snapshot.isSecure) {
1046 snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::DROP_INPUT;
1047 }
1048
1049 if (requested.touchCropId != UNASSIGNED_LAYER_ID || path.isClone()) {
1050 mNeedsTouchableRegionCrop.insert(path);
1051 }
1052 auto cropLayerSnapshot = getSnapshot(requested.touchCropId);
1053 if (!cropLayerSnapshot && snapshot.inputInfo.replaceTouchableRegionWithCrop) {
1054 FloatRect inputBounds = getInputBounds(snapshot, /*fillParentBounds=*/true).first;
1055 Rect inputBoundsInDisplaySpace =
1056 getInputBoundsInDisplaySpace(snapshot, inputBounds, displayInfo.transform);
1057 snapshot.inputInfo.touchableRegion = Region(inputBoundsInDisplaySpace);
1058 }
1059
1060 // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
1061 // if it was set by WM for a known system overlay
1062 if (snapshot.isTrustedOverlay) {
1063 snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::TRUSTED_OVERLAY;
1064 }
1065
1066 // If the layer is a clone, we need to crop the input region to cloned root to prevent
1067 // touches from going outside the cloned area.
1068 if (path.isClone()) {
1069 snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::CLONE;
1070 // Cloned layers shouldn't handle watch outside since their z order is not determined by
1071 // WM or the client.
1072 snapshot.inputInfo.inputConfig.clear(gui::WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH);
1073 }
1074 }
1075
getSnapshots()1076 std::vector<std::unique_ptr<LayerSnapshot>>& LayerSnapshotBuilder::getSnapshots() {
1077 return mSnapshots;
1078 }
1079
forEachVisibleSnapshot(const ConstVisitor & visitor) const1080 void LayerSnapshotBuilder::forEachVisibleSnapshot(const ConstVisitor& visitor) const {
1081 for (int i = 0; i < mNumInterestingSnapshots; i++) {
1082 LayerSnapshot& snapshot = *mSnapshots[(size_t)i];
1083 if (!snapshot.isVisible) continue;
1084 visitor(snapshot);
1085 }
1086 }
1087
1088 // Visit each visible snapshot in z-order
forEachVisibleSnapshot(const ConstVisitor & visitor,const LayerHierarchy & root) const1089 void LayerSnapshotBuilder::forEachVisibleSnapshot(const ConstVisitor& visitor,
1090 const LayerHierarchy& root) const {
1091 root.traverseInZOrder(
1092 [this, visitor](const LayerHierarchy&,
1093 const LayerHierarchy::TraversalPath& traversalPath) -> bool {
1094 LayerSnapshot* snapshot = getSnapshot(traversalPath);
1095 if (snapshot && snapshot->isVisible) {
1096 visitor(*snapshot);
1097 }
1098 return true;
1099 });
1100 }
1101
forEachVisibleSnapshot(const Visitor & visitor)1102 void LayerSnapshotBuilder::forEachVisibleSnapshot(const Visitor& visitor) {
1103 for (int i = 0; i < mNumInterestingSnapshots; i++) {
1104 std::unique_ptr<LayerSnapshot>& snapshot = mSnapshots.at((size_t)i);
1105 if (!snapshot->isVisible) continue;
1106 visitor(snapshot);
1107 }
1108 }
1109
forEachInputSnapshot(const ConstVisitor & visitor) const1110 void LayerSnapshotBuilder::forEachInputSnapshot(const ConstVisitor& visitor) const {
1111 for (int i = mNumInterestingSnapshots - 1; i >= 0; i--) {
1112 LayerSnapshot& snapshot = *mSnapshots[(size_t)i];
1113 if (!snapshot.hasInputInfo()) continue;
1114 visitor(snapshot);
1115 }
1116 }
1117
updateTouchableRegionCrop(const Args & args)1118 void LayerSnapshotBuilder::updateTouchableRegionCrop(const Args& args) {
1119 if (mNeedsTouchableRegionCrop.empty()) {
1120 return;
1121 }
1122
1123 static constexpr ftl::Flags<RequestedLayerState::Changes> AFFECTS_INPUT =
1124 RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Created |
1125 RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Geometry |
1126 RequestedLayerState::Changes::Input;
1127
1128 if (args.forceUpdate != ForceUpdateFlags::ALL &&
1129 !args.layerLifecycleManager.getGlobalChanges().any(AFFECTS_INPUT) && !args.displayChanges) {
1130 return;
1131 }
1132
1133 for (auto& path : mNeedsTouchableRegionCrop) {
1134 frontend::LayerSnapshot* snapshot = getSnapshot(path);
1135 if (!snapshot) {
1136 continue;
1137 }
1138 LLOGV(snapshot->sequence, "updateTouchableRegionCrop=%s",
1139 snapshot->getDebugString().c_str());
1140 const std::optional<frontend::DisplayInfo> displayInfoOpt =
1141 args.displays.get(snapshot->outputFilter.layerStack);
1142 static frontend::DisplayInfo sDefaultInfo = {.isSecure = false};
1143 auto displayInfo = displayInfoOpt.value_or(sDefaultInfo);
1144
1145 bool needsUpdate =
1146 args.forceUpdate == ForceUpdateFlags::ALL || snapshot->changes.any(AFFECTS_INPUT);
1147 auto cropLayerSnapshot = getSnapshot(snapshot->touchCropId);
1148 needsUpdate =
1149 needsUpdate || (cropLayerSnapshot && cropLayerSnapshot->changes.any(AFFECTS_INPUT));
1150 auto clonedRootSnapshot = path.isClone() ? getSnapshot(snapshot->mirrorRootPath) : nullptr;
1151 needsUpdate = needsUpdate ||
1152 (clonedRootSnapshot && clonedRootSnapshot->changes.any(AFFECTS_INPUT));
1153
1154 if (!needsUpdate) {
1155 continue;
1156 }
1157
1158 if (snapshot->inputInfo.replaceTouchableRegionWithCrop) {
1159 Rect inputBoundsInDisplaySpace;
1160 if (!cropLayerSnapshot) {
1161 FloatRect inputBounds = getInputBounds(*snapshot, /*fillParentBounds=*/true).first;
1162 inputBoundsInDisplaySpace =
1163 getInputBoundsInDisplaySpace(*snapshot, inputBounds, displayInfo.transform);
1164 } else {
1165 FloatRect inputBounds =
1166 getInputBounds(*cropLayerSnapshot, /*fillParentBounds=*/true).first;
1167 inputBoundsInDisplaySpace =
1168 getInputBoundsInDisplaySpace(*cropLayerSnapshot, inputBounds,
1169 displayInfo.transform);
1170 }
1171 snapshot->inputInfo.touchableRegion = Region(inputBoundsInDisplaySpace);
1172 } else if (cropLayerSnapshot) {
1173 FloatRect inputBounds =
1174 getInputBounds(*cropLayerSnapshot, /*fillParentBounds=*/true).first;
1175 Rect inputBoundsInDisplaySpace =
1176 getInputBoundsInDisplaySpace(*cropLayerSnapshot, inputBounds,
1177 displayInfo.transform);
1178 snapshot->inputInfo.touchableRegion = snapshot->inputInfo.touchableRegion.intersect(
1179 displayInfo.transform.transform(inputBoundsInDisplaySpace));
1180 }
1181
1182 // If the layer is a clone, we need to crop the input region to cloned root to prevent
1183 // touches from going outside the cloned area.
1184 if (clonedRootSnapshot) {
1185 const Rect rect =
1186 displayInfo.transform.transform(Rect{clonedRootSnapshot->transformedBounds});
1187 snapshot->inputInfo.touchableRegion =
1188 snapshot->inputInfo.touchableRegion.intersect(rect);
1189 }
1190 }
1191 }
1192
1193 } // namespace android::surfaceflinger::frontend
1194