blob: 3caeebec2a18e4b63f6ce4d78ea1664c7f0ef2c4 [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 ATRACE_TAG ATRACE_TAG_GRAPHICS
18#undef LOG_TAG
19#define LOG_TAG "LayerSnapshot"
20
21#include "LayerSnapshot.h"
22
23namespace android::surfaceflinger::frontend {
24
25using namespace ftl::flag_operators;
26
27LayerSnapshot::LayerSnapshot(const RequestedLayerState& state,
28 const LayerHierarchy::TraversalPath& path)
29 : path(path) {
Vishnu Naird0183602023-03-16 18:52:15 +000030 // Provide a unique id for all snapshots.
31 // A front end layer can generate multiple snapshots if its mirrored.
32 // Additionally, if the layer is not reachable, we may choose to destroy
33 // and recreate the snapshot in which case the unique sequence id will
34 // change. The consumer shouldn't tie any lifetimes to this unique id but
35 // register a LayerLifecycleManager::ILifecycleListener or get a list of
36 // destroyed layers from LayerLifecycleManager.
Vishnu Nair150065b2023-04-17 19:14:11 -070037 if (path.isClone()) {
38 uniqueSequence =
39 LayerCreationArgs::getInternalLayerId(LayerCreationArgs::sInternalSequence++);
40 } else {
41 uniqueSequence = state.id;
42 }
Vishnu Nair8fc721b2022-12-22 20:06:32 +000043 sequence = static_cast<int32_t>(state.id);
44 name = state.name;
45 textureName = state.textureName;
46 premultipliedAlpha = state.premultipliedAlpha;
47 inputInfo.name = state.name;
Vishnu Nair93b8b792023-02-27 19:40:24 +000048 inputInfo.id = static_cast<int32_t>(uniqueSequence);
Prabir Pradhan8a5c41d2023-06-08 19:13:46 +000049 inputInfo.ownerUid = gui::Uid{state.ownerUid};
Prabir Pradhane59c6dc2023-06-13 19:53:03 +000050 inputInfo.ownerPid = gui::Pid{state.ownerPid};
Vishnu Nair36d5f8e2023-03-19 13:31:35 -070051 uid = state.ownerUid;
52 pid = state.ownerPid;
Vishnu Nair92990e22023-02-24 20:01:05 +000053 changes = RequestedLayerState::Changes::Created;
54 mirrorRootPath = path.variant == LayerHierarchy::Variant::Mirror
55 ? path
56 : LayerHierarchy::TraversalPath::ROOT;
Vishnu Nair8fc721b2022-12-22 20:06:32 +000057}
58
59// As documented in libhardware header, formats in the range
60// 0x100 - 0x1FF are specific to the HAL implementation, and
61// are known to have no alpha channel
62// TODO: move definition for device-specific range into
63// hardware.h, instead of using hard-coded values here.
64#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
65
66bool LayerSnapshot::isOpaqueFormat(PixelFormat format) {
67 if (HARDWARE_IS_DEVICE_FORMAT(format)) {
68 return true;
69 }
70 switch (format) {
71 case PIXEL_FORMAT_RGBA_8888:
72 case PIXEL_FORMAT_BGRA_8888:
73 case PIXEL_FORMAT_RGBA_FP16:
74 case PIXEL_FORMAT_RGBA_1010102:
75 case PIXEL_FORMAT_R_8:
76 return false;
77 }
78 // in all other case, we have no blending (also for unknown formats)
79 return true;
80}
81
82bool LayerSnapshot::hasBufferOrSidebandStream() const {
Vishnu Naircfb2d252023-01-19 04:44:02 +000083 return ((sidebandStream != nullptr) || (externalTexture != nullptr));
Vishnu Nair8fc721b2022-12-22 20:06:32 +000084}
85
86bool LayerSnapshot::drawShadows() const {
87 return shadowSettings.length > 0.f;
88}
89
90bool LayerSnapshot::fillsColor() const {
91 return !hasBufferOrSidebandStream() && color.r >= 0.0_hf && color.g >= 0.0_hf &&
92 color.b >= 0.0_hf;
93}
94
95bool LayerSnapshot::hasBlur() const {
96 return backgroundBlurRadius > 0 || blurRegions.size() > 0;
97}
98
99bool LayerSnapshot::hasEffect() const {
100 return fillsColor() || drawShadows() || hasBlur();
101}
102
103bool LayerSnapshot::hasSomethingToDraw() const {
104 return hasEffect() || hasBufferOrSidebandStream();
105}
106
107bool LayerSnapshot::isContentOpaque() const {
108 // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
109 // layer's opaque flag.
110 if (!hasSomethingToDraw()) {
111 return false;
112 }
113
114 // if the layer has the opaque flag, then we're always opaque
115 if (layerOpaqueFlagSet) {
116 return true;
117 }
118
119 // If the buffer has no alpha channel, then we are opaque
120 if (hasBufferOrSidebandStream() &&
Vishnu Naircfb2d252023-01-19 04:44:02 +0000121 isOpaqueFormat(externalTexture ? externalTexture->getPixelFormat() : PIXEL_FORMAT_NONE)) {
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000122 return true;
123 }
124
125 // Lastly consider the layer opaque if drawing a color with alpha == 1.0
126 return fillsColor() && color.a == 1.0_hf;
127}
128
129bool LayerSnapshot::isHiddenByPolicy() const {
Vishnu Naircfb2d252023-01-19 04:44:02 +0000130 return invalidTransform || isHiddenByPolicyFromParent || isHiddenByPolicyFromRelativeParent;
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000131}
132
133bool LayerSnapshot::getIsVisible() const {
Vishnu Naira9c43762023-01-27 19:10:25 +0000134 if (handleSkipScreenshotFlag & outputFilter.toInternalDisplay) {
135 return false;
136 }
137
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000138 if (!hasSomethingToDraw()) {
139 return false;
140 }
141
142 if (isHiddenByPolicy()) {
143 return false;
144 }
145
146 return color.a > 0.0f || hasBlur();
147}
148
149std::string LayerSnapshot::getIsVisibleReason() const {
Vishnu Naircfb2d252023-01-19 04:44:02 +0000150 // not visible
Vishnu Naira9c43762023-01-27 19:10:25 +0000151 if (handleSkipScreenshotFlag & outputFilter.toInternalDisplay) return "eLayerSkipScreenshot";
Vishnu Naircfb2d252023-01-19 04:44:02 +0000152 if (!hasSomethingToDraw()) return "!hasSomethingToDraw";
153 if (invalidTransform) return "invalidTransform";
154 if (isHiddenByPolicyFromParent) return "hidden by parent or layer flag";
155 if (isHiddenByPolicyFromRelativeParent) return "hidden by relative parent";
156 if (color.a == 0.0f && !hasBlur()) return "alpha = 0 and no blur";
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000157
Vishnu Naircfb2d252023-01-19 04:44:02 +0000158 // visible
159 std::stringstream reason;
160 if (sidebandStream != nullptr) reason << " sidebandStream";
Vishnu Naird47bcee2023-02-24 18:08:51 +0000161 if (externalTexture != nullptr)
162 reason << " buffer:" << externalTexture->getId() << " frame:" << frameNumber;
Vishnu Naircfb2d252023-01-19 04:44:02 +0000163 if (fillsColor() || color.a > 0.0f) reason << " color{" << color << "}";
164 if (drawShadows()) reason << " shadowSettings.length=" << shadowSettings.length;
165 if (backgroundBlurRadius > 0) reason << " backgroundBlurRadius=" << backgroundBlurRadius;
166 if (blurRegions.size() > 0) reason << " blurRegions.size()=" << blurRegions.size();
167 return reason.str();
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000168}
169
170bool LayerSnapshot::canReceiveInput() const {
171 return !isHiddenByPolicy() && (!hasBufferOrSidebandStream() || color.a > 0.0f);
172}
173
174bool LayerSnapshot::isTransformValid(const ui::Transform& t) {
175 float transformDet = t.det();
176 return transformDet != 0 && !isinf(transformDet) && !isnan(transformDet);
177}
178
Vishnu Naircfb2d252023-01-19 04:44:02 +0000179bool LayerSnapshot::hasInputInfo() const {
180 return inputInfo.token != nullptr ||
181 inputInfo.inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
182}
183
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000184std::string LayerSnapshot::getDebugString() const {
Vishnu Naircfb2d252023-01-19 04:44:02 +0000185 std::stringstream debug;
186 debug << "Snapshot{" << path.toString() << name << " isVisible=" << isVisible << " {"
Vishnu Nair92990e22023-02-24 20:01:05 +0000187 << getIsVisibleReason() << "} changes=" << changes.string()
Vishnu Nair36d5f8e2023-03-19 13:31:35 -0700188 << " layerStack=" << outputFilter.layerStack.id << " geomLayerBounds={"
189 << geomLayerBounds.left << "," << geomLayerBounds.top << "," << geomLayerBounds.bottom
190 << "," << geomLayerBounds.right << "}"
191 << " geomLayerTransform={tx=" << geomLayerTransform.tx()
192 << ",ty=" << geomLayerTransform.ty() << "}"
193 << "}";
Vishnu Nair29354ec2023-03-28 18:51:28 -0700194 debug << " input{ touchCropId=" << touchCropId
195 << " replaceTouchableRegionWithCrop=" << inputInfo.replaceTouchableRegionWithCrop << "}";
Vishnu Naircfb2d252023-01-19 04:44:02 +0000196 return debug.str();
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000197}
198
Vishnu Nair781d7252023-01-30 18:16:01 +0000199FloatRect LayerSnapshot::sourceBounds() const {
200 if (!externalTexture) {
201 return geomLayerBounds;
202 }
203 return geomBufferSize.toFloatRect();
204}
205
Vishnu Nair8fc721b2022-12-22 20:06:32 +0000206} // namespace android::surfaceflinger::frontend