SF: LayerSnapshotBuilder updates
- Adds support for framerate, gamemode, transformhint & input
- Fixes z-order traversal bug where a layer was visited twice.
- Compat fix, a layer cannot be root once its parented
Test: presubmit
Bug: 238781169
Change-Id: Ic33aa09b2c41fadd4872ca481b41f86400629fc8
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 0982077..d76faba 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -166,7 +166,8 @@
.receivesInput = receivesInput(),
.isSecure = isSecure(),
.isPrimary = isPrimary(),
- .rotationFlags = ui::Transform::toRotationFlags(mOrientation)};
+ .rotationFlags = ui::Transform::toRotationFlags(mOrientation),
+ .transformHint = getTransformHint()};
}
void DisplayDevice::setPowerMode(hal::PowerMode mode) {
diff --git a/services/surfaceflinger/FrontEnd/DisplayInfo.h b/services/surfaceflinger/FrontEnd/DisplayInfo.h
index 0c7b24a..6b9d7a2 100644
--- a/services/surfaceflinger/FrontEnd/DisplayInfo.h
+++ b/services/surfaceflinger/FrontEnd/DisplayInfo.h
@@ -16,6 +16,8 @@
#pragma once
+#include <sstream>
+
#include <gui/DisplayInfo.h>
namespace android::surfaceflinger::frontend {
@@ -29,6 +31,16 @@
// TODO(b/238781169) can eliminate once sPrimaryDisplayRotationFlags is removed.
bool isPrimary;
ui::Transform::RotationFlags rotationFlags;
+ ui::Transform::RotationFlags transformHint;
+ std::string getDebugString() const {
+ std::stringstream debug;
+ debug << "DisplayInfo {displayId=" << info.displayId << " lw=" << info.logicalWidth
+ << " lh=" << info.logicalHeight << " transform={" << transform.dsdx() << " ,"
+ << transform.dsdy() << " ," << transform.dtdx() << " ," << transform.dtdy()
+ << "} isSecure=" << isSecure << " isPrimary=" << isPrimary
+ << " rotationFlags=" << rotationFlags << " transformHint=" << transformHint << "}";
+ return debug.str();
+ }
};
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
index 514a642..678d36b 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
@@ -28,8 +28,8 @@
const std::pair<LayerHierarchy*, LayerHierarchy::Variant>& rhs) {
auto lhsLayer = lhs.first->getLayer();
auto rhsLayer = rhs.first->getLayer();
- if (lhsLayer->layerStack != rhsLayer->layerStack) {
- return lhsLayer->layerStack.id < rhsLayer->layerStack.id;
+ if (lhsLayer->layerStack.id != rhsLayer->layerStack.id) {
+ return lhsLayer->layerStack.id > rhsLayer->layerStack.id;
}
if (lhsLayer->z != rhsLayer->z) {
return lhsLayer->z < rhsLayer->z;
@@ -75,11 +75,11 @@
for (auto it = mChildren.begin(); it < mChildren.end(); it++) {
auto& [child, childVariant] = *it;
if (traverseThisLayer && child->getLayer()->z >= 0) {
+ traverseThisLayer = false;
bool breakTraversal = !visitor(*this, traversalPath);
if (breakTraversal) {
return;
}
- traverseThisLayer = false;
}
if (childVariant == LayerHierarchy::Variant::Detached) {
continue;
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
index 8cdc240..ca8d301 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
@@ -41,11 +41,13 @@
// states.
class LayerHierarchy {
public:
- enum Variant {
+ enum Variant : uint32_t {
Attached,
Detached,
Relative,
Mirror,
+ ftl_first = Attached,
+ ftl_last = Mirror,
};
// Represents a unique path to a node.
struct TraversalPath {
diff --git a/services/surfaceflinger/FrontEnd/LayerLog.h b/services/surfaceflinger/FrontEnd/LayerLog.h
new file mode 100644
index 0000000..47e1e30
--- /dev/null
+++ b/services/surfaceflinger/FrontEnd/LayerLog.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// Uncomment to trace layer updates for a single layer
+// #define LOG_LAYER 1
+
+#ifdef LOG_LAYER
+#define LLOGV(LAYER_ID, x, ...) \
+ ALOGV_IF(((LAYER_ID) == LOG_LAYER), "[%d] %s " x, LOG_LAYER, __func__, ##__VA_ARGS__);
+#else
+#define LLOGV(LAYER_ID, x, ...) ALOGV("[%d] %s " x, (LAYER_ID), __func__, ##__VA_ARGS__);
+#endif
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index d483a99..3a0540c 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -61,7 +61,7 @@
}
bool LayerSnapshot::hasBufferOrSidebandStream() const {
- return ((sidebandStream != nullptr) || (buffer != nullptr));
+ return ((sidebandStream != nullptr) || (externalTexture != nullptr));
}
bool LayerSnapshot::drawShadows() const {
@@ -99,7 +99,7 @@
// If the buffer has no alpha channel, then we are opaque
if (hasBufferOrSidebandStream() &&
- isOpaqueFormat(buffer ? buffer->getPixelFormat() : PIXEL_FORMAT_NONE)) {
+ isOpaqueFormat(externalTexture ? externalTexture->getPixelFormat() : PIXEL_FORMAT_NONE)) {
return true;
}
@@ -108,11 +108,7 @@
}
bool LayerSnapshot::isHiddenByPolicy() const {
- if (CC_UNLIKELY(invalidTransform)) {
- ALOGW("Hide layer %s because it has invalid transformation.", name.c_str());
- return true;
- }
- return isHiddenByPolicyFromParent || isHiddenByPolicyFromRelativeParent;
+ return invalidTransform || isHiddenByPolicyFromParent || isHiddenByPolicyFromRelativeParent;
}
bool LayerSnapshot::getIsVisible() const {
@@ -128,19 +124,22 @@
}
std::string LayerSnapshot::getIsVisibleReason() const {
- if (!hasSomethingToDraw()) {
- return "!hasSomethingToDraw";
- }
+ // not visible
+ if (!hasSomethingToDraw()) return "!hasSomethingToDraw";
+ if (invalidTransform) return "invalidTransform";
+ if (isHiddenByPolicyFromParent) return "hidden by parent or layer flag";
+ if (isHiddenByPolicyFromRelativeParent) return "hidden by relative parent";
+ if (color.a == 0.0f && !hasBlur()) return "alpha = 0 and no blur";
- if (isHiddenByPolicy()) {
- return "isHiddenByPolicy";
- }
-
- if (color.a > 0.0f || hasBlur()) {
- return "";
- }
-
- return "alpha = 0 and !hasBlur";
+ // visible
+ std::stringstream reason;
+ if (sidebandStream != nullptr) reason << " sidebandStream";
+ if (externalTexture != nullptr) reason << " buffer";
+ if (fillsColor() || color.a > 0.0f) reason << " color{" << color << "}";
+ if (drawShadows()) reason << " shadowSettings.length=" << shadowSettings.length;
+ if (backgroundBlurRadius > 0) reason << " backgroundBlurRadius=" << backgroundBlurRadius;
+ if (blurRegions.size() > 0) reason << " blurRegions.size()=" << blurRegions.size();
+ return reason.str();
}
bool LayerSnapshot::canReceiveInput() const {
@@ -152,11 +151,16 @@
return transformDet != 0 && !isinf(transformDet) && !isnan(transformDet);
}
+bool LayerSnapshot::hasInputInfo() const {
+ return inputInfo.token != nullptr ||
+ inputInfo.inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
+}
+
std::string LayerSnapshot::getDebugString() const {
- return "Snapshot(" + base::StringPrintf("%p", this) + "){" + path.toString() + name +
- " isHidden=" + std::to_string(isHiddenByPolicyFromParent) +
- " isHiddenRelative=" + std::to_string(isHiddenByPolicyFromRelativeParent) +
- " isVisible=" + std::to_string(isVisible) + " " + getIsVisibleReason() + "}";
+ std::stringstream debug;
+ debug << "Snapshot{" << path.toString() << name << " isVisible=" << isVisible << " {"
+ << getIsVisibleReason() << "} changes=" << changes.string() << "}";
+ return debug.str();
}
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index d14bd3a..4512ade 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -20,6 +20,7 @@
#include <renderengine/LayerSettings.h>
#include "LayerHierarchy.h"
#include "RequestedLayerState.h"
+#include "Scheduler/LayerInfo.h"
#include "android-base/stringprintf.h"
namespace android::surfaceflinger::frontend {
@@ -39,6 +40,10 @@
}
};
+struct ChildState {
+ bool hasValidFrameRate = false;
+};
+
// LayerSnapshot stores Layer state used by CompositionEngine and RenderEngine. Composition
// Engine uses a pointer to LayerSnapshot (as LayerFECompositionState*) and the LayerSettings
// passed to Render Engine are created using properties stored on this struct.
@@ -59,6 +64,7 @@
bool layerOpaqueFlagSet;
RoundedCornerState roundedCorner;
FloatRect transformedBounds;
+ Rect transformedBoundsWithoutTransparentRegion;
renderengine::ShadowSettings shadowSettings;
bool premultipliedAlpha;
bool isHdrY410;
@@ -75,6 +81,10 @@
ui::Transform localTransform;
gui::DropInputMode dropInputMode;
bool isTrustedOverlay;
+ gui::GameMode gameMode;
+ scheduler::LayerInfo::FrameRate frameRate;
+ ui::Transform::RotationFlags fixedTransformHint;
+ ChildState childState;
static bool isOpaqueFormat(PixelFormat format);
static bool isTransformValid(const ui::Transform& t);
@@ -91,6 +101,7 @@
bool isHiddenByPolicy() const;
std::string getDebugString() const;
std::string getIsVisibleReason() const;
+ bool hasInputInfo() const;
};
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index bff12d7..40dffb9 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -24,6 +24,8 @@
#include <numeric>
#include "DisplayHardware/HWC2.h"
#include "DisplayHardware/Hal.h"
+#include "LayerLog.h"
+#include "TimeStats/TimeStats.h"
#include "ftl/small_map.h"
namespace android::surfaceflinger::frontend {
@@ -250,6 +252,64 @@
return blendMode;
}
+void updateSurfaceDamage(const RequestedLayerState& requested, bool hasReadyFrame,
+ bool forceFullDamage, Region& outSurfaceDamageRegion) {
+ if (!hasReadyFrame) {
+ outSurfaceDamageRegion.clear();
+ return;
+ }
+ if (forceFullDamage) {
+ outSurfaceDamageRegion = Region::INVALID_REGION;
+ } else {
+ outSurfaceDamageRegion = requested.surfaceDamageRegion;
+ }
+}
+
+void updateVisibility(LayerSnapshot& snapshot) {
+ snapshot.isVisible = snapshot.getIsVisible();
+
+ // TODO(b/238781169) we are ignoring this compat for now, since we will have
+ // to remove any optimization based on visibility.
+
+ // For compatibility reasons we let layers which can receive input
+ // receive input before they have actually submitted a buffer. Because
+ // of this we use canReceiveInput instead of isVisible to check the
+ // policy-visibility, ignoring the buffer state. However for layers with
+ // hasInputInfo()==false we can use the real visibility state.
+ // We are just using these layers for occlusion detection in
+ // InputDispatcher, and obviously if they aren't visible they can't occlude
+ // anything.
+ const bool visible =
+ (snapshot.inputInfo.token != nullptr) ? snapshot.canReceiveInput() : snapshot.isVisible;
+ snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible);
+}
+
+bool needsInputInfo(const LayerSnapshot& snapshot, const RequestedLayerState& requested) {
+ if (requested.potentialCursor) {
+ return false;
+ }
+
+ if (snapshot.inputInfo.token != nullptr) {
+ return true;
+ }
+
+ if (snapshot.hasBufferOrSidebandStream()) {
+ return true;
+ }
+
+ return requested.windowInfoHandle &&
+ requested.windowInfoHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
+}
+
+void clearChanges(LayerSnapshot& snapshot) {
+ snapshot.changes.clear();
+ snapshot.contentDirty = false;
+ snapshot.hasReadyFrame = false;
+ snapshot.sidebandStreamHasFrame = false;
+ snapshot.surfaceDamage.clear();
+}
+
} // namespace
LayerSnapshot LayerSnapshotBuilder::getRootSnapshot() {
@@ -274,6 +334,9 @@
snapshot.inputInfo.touchOcclusionMode = gui::TouchOcclusionMode::BLOCK_UNTRUSTED;
snapshot.dropInputMode = gui::DropInputMode::NONE;
snapshot.isTrustedOverlay = false;
+ snapshot.gameMode = gui::GameMode::Unsupported;
+ snapshot.frameRate = {};
+ snapshot.fixedTransformHint = ui::Transform::ROT_INVALID;
return snapshot;
}
@@ -285,16 +348,15 @@
}
bool LayerSnapshotBuilder::tryFastUpdate(const Args& args) {
- if (args.forceUpdate) {
- // force update requested, so skip the fast path
+ if (args.forceUpdate || args.displayChanges) {
+ // force update requested, or we have display changes, so skip the fast path
return false;
}
if (args.layerLifecycleManager.getGlobalChanges().get() == 0) {
// there are no changes, so just clear the change flags from before.
for (auto& snapshot : mSnapshots) {
- snapshot->changes.clear();
- snapshot->contentDirty = false;
+ clearChanges(*snapshot);
}
return true;
}
@@ -320,14 +382,14 @@
// Walk through the snapshots, clearing previous change flags and updating the snapshots
// if needed.
for (auto& snapshot : mSnapshots) {
- snapshot->changes.clear();
- snapshot->contentDirty = false;
+ clearChanges(*snapshot);
auto it = layersWithChanges.find(snapshot->path.id);
if (it != layersWithChanges.end()) {
ALOGV("%s fast path snapshot changes = %s", __func__,
mRootSnapshot.changes.string().c_str());
LayerHierarchy::TraversalPath root = LayerHierarchy::TraversalPath::ROOT;
- updateSnapshot(*snapshot, args, *it->second, mRootSnapshot, root);
+ updateSnapshot(*snapshot, args, *it->second, mRootSnapshot, root,
+ /*newSnapshot=*/false);
}
}
return true;
@@ -335,7 +397,6 @@
void LayerSnapshotBuilder::updateSnapshots(const Args& args) {
ATRACE_NAME("UpdateSnapshots");
- ALOGV("%s updateSnapshots force = %s", __func__, std::to_string(args.forceUpdate).c_str());
if (args.forceUpdate || args.displayChanges) {
mRootSnapshot.geomLayerBounds = getMaxDisplayBounds(args.displays);
}
@@ -352,7 +413,7 @@
}
sortSnapshotsByZ(args);
- mRootSnapshot.changes.clear();
+ clearChanges(mRootSnapshot);
// Destroy unreachable snapshots
if (args.layerLifecycleManager.getDestroyedLayers().empty()) {
@@ -372,6 +433,7 @@
}
mIdToSnapshot.erase(traversalPath);
+ mSnapshots.back()->globalZ = it->get()->globalZ;
std::iter_swap(it, mSnapshots.end() - 1);
mSnapshots.erase(mSnapshots.end() - 1);
}
@@ -384,12 +446,15 @@
updateSnapshots(args);
}
-void LayerSnapshotBuilder::updateSnapshotsInHierarchy(const Args& args,
- const LayerHierarchy& hierarchy,
- LayerHierarchy::TraversalPath& traversalPath,
- const LayerSnapshot& parentSnapshot) {
+const LayerSnapshot& LayerSnapshotBuilder::updateSnapshotsInHierarchy(
+ const Args& args, const LayerHierarchy& hierarchy,
+ LayerHierarchy::TraversalPath& traversalPath, const LayerSnapshot& parentSnapshot) {
const RequestedLayerState* layer = hierarchy.getLayer();
- LayerSnapshot* snapshot = getOrCreateSnapshot(traversalPath, *layer);
+ LayerSnapshot* snapshot = getSnapshot(traversalPath);
+ const bool newSnapshot = snapshot == nullptr;
+ if (newSnapshot) {
+ snapshot = createSnapshot(traversalPath, *layer);
+ }
if (traversalPath.isRelative()) {
bool parentIsRelative = traversalPath.variant == LayerHierarchy::Variant::Relative;
updateRelativeState(*snapshot, parentSnapshot, parentIsRelative, args);
@@ -397,23 +462,18 @@
if (traversalPath.isAttached()) {
resetRelativeState(*snapshot);
}
- updateSnapshot(*snapshot, args, *layer, parentSnapshot, traversalPath);
- }
-
- // If layer is hidden by policy we can avoid update its children. If the visibility
- // changed this update, then we still need to set the visibility on all the children.
- if (snapshot->isHiddenByPolicy() &&
- (!snapshot->changes.any(RequestedLayerState::Changes::Visibility |
- RequestedLayerState::Changes::Hierarchy))) {
- return;
+ updateSnapshot(*snapshot, args, *layer, parentSnapshot, traversalPath, newSnapshot);
}
for (auto& [childHierarchy, variant] : hierarchy.mChildren) {
LayerHierarchy::ScopedAddToTraversalPath addChildToPath(traversalPath,
childHierarchy->getLayer()->id,
variant);
- updateSnapshotsInHierarchy(args, *childHierarchy, traversalPath, *snapshot);
+ const LayerSnapshot& childSnapshot =
+ updateSnapshotsInHierarchy(args, *childHierarchy, traversalPath, *snapshot);
+ updateChildState(*snapshot, childSnapshot, args);
}
+ return *snapshot;
}
LayerSnapshot* LayerSnapshotBuilder::getSnapshot(uint32_t layerId) const {
@@ -429,22 +489,17 @@
return it == mIdToSnapshot.end() ? nullptr : it->second;
}
-LayerSnapshot* LayerSnapshotBuilder::getOrCreateSnapshot(const LayerHierarchy::TraversalPath& id,
- const RequestedLayerState& layer) {
- auto snapshot = getSnapshot(id);
- if (snapshot) {
- return snapshot;
- }
-
+LayerSnapshot* LayerSnapshotBuilder::createSnapshot(const LayerHierarchy::TraversalPath& id,
+ const RequestedLayerState& layer) {
mSnapshots.emplace_back(std::make_unique<LayerSnapshot>(layer, id));
- snapshot = mSnapshots.back().get();
+ LayerSnapshot* snapshot = mSnapshots.back().get();
snapshot->globalZ = static_cast<size_t>(mSnapshots.size()) - 1;
mIdToSnapshot[id] = snapshot;
return snapshot;
}
void LayerSnapshotBuilder::sortSnapshotsByZ(const Args& args) {
- if (!args.forceUpdate &&
+ if (!mResortSnapshots && !args.forceUpdate &&
!args.layerLifecycleManager.getGlobalChanges().any(
RequestedLayerState::Changes::Hierarchy |
RequestedLayerState::Changes::Visibility)) {
@@ -453,6 +508,8 @@
return;
}
+ mResortSnapshots = false;
+
size_t globalZ = 0;
args.root.traverseInZOrder(
[this, &globalZ](const LayerHierarchy&,
@@ -467,7 +524,8 @@
return false;
}
- if (snapshot->isVisible) {
+ if (snapshot->getIsVisible() || snapshot->hasInputInfo()) {
+ updateVisibility(*snapshot);
size_t oldZ = snapshot->globalZ;
size_t newZ = globalZ++;
snapshot->globalZ = newZ;
@@ -475,16 +533,17 @@
return true;
}
mSnapshots[newZ]->globalZ = oldZ;
+ LLOGV(snapshot->sequence, "Made visible z=%zu -> %zu %s", oldZ, newZ,
+ snapshot->getDebugString().c_str());
std::iter_swap(mSnapshots.begin() + static_cast<ssize_t>(oldZ),
mSnapshots.begin() + static_cast<ssize_t>(newZ));
}
-
return true;
});
-
+ mNumInterestingSnapshots = (int)globalZ;
while (globalZ < mSnapshots.size()) {
mSnapshots[globalZ]->globalZ = globalZ;
- mSnapshots[globalZ]->isVisible = false;
+ updateVisibility(*mSnapshots[globalZ]);
globalZ++;
}
}
@@ -493,7 +552,8 @@
const LayerSnapshot& parentSnapshot,
bool parentIsRelative, const Args& args) {
if (parentIsRelative) {
- snapshot.isHiddenByPolicyFromRelativeParent = parentSnapshot.isHiddenByPolicyFromParent;
+ snapshot.isHiddenByPolicyFromRelativeParent =
+ parentSnapshot.isHiddenByPolicyFromParent || parentSnapshot.invalidTransform;
if (args.includeMetadata) {
snapshot.relativeLayerMetadata = parentSnapshot.layerMetadata;
}
@@ -507,6 +567,38 @@
snapshot.isVisible = snapshot.getIsVisible();
}
+void LayerSnapshotBuilder::updateChildState(LayerSnapshot& snapshot,
+ const LayerSnapshot& childSnapshot, const Args& args) {
+ if (snapshot.childState.hasValidFrameRate) {
+ return;
+ }
+ if (args.forceUpdate || childSnapshot.changes.test(RequestedLayerState::Changes::FrameRate)) {
+ // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes
+ // for the same reason we are allowing touch boost for those layers. See
+ // RefreshRateSelector::rankFrameRates for details.
+ using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility;
+ const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.rate.isValid() &&
+ childSnapshot.frameRate.type == FrameRateCompatibility::Default;
+ const auto layerVotedWithNoVote =
+ childSnapshot.frameRate.type == FrameRateCompatibility::NoVote;
+ const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.rate.isValid() &&
+ childSnapshot.frameRate.type == FrameRateCompatibility::Exact;
+
+ snapshot.childState.hasValidFrameRate |= layerVotedWithDefaultCompatibility ||
+ layerVotedWithNoVote || layerVotedWithExactCompatibility;
+
+ // If we don't have a valid frame rate, but the children do, we set this
+ // layer as NoVote to allow the children to control the refresh rate
+ if (!snapshot.frameRate.rate.isValid() &&
+ snapshot.frameRate.type != FrameRateCompatibility::NoVote &&
+ snapshot.childState.hasValidFrameRate) {
+ snapshot.frameRate =
+ scheduler::LayerInfo::FrameRate(Fps(), FrameRateCompatibility::NoVote);
+ snapshot.changes |= childSnapshot.changes & RequestedLayerState::Changes::FrameRate;
+ }
+ }
+}
+
void LayerSnapshotBuilder::resetRelativeState(LayerSnapshot& snapshot) {
snapshot.isHiddenByPolicyFromRelativeParent = false;
snapshot.relativeLayerMetadata.mMap.clear();
@@ -523,27 +615,69 @@
void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& args,
const RequestedLayerState& requested,
const LayerSnapshot& parentSnapshot,
- const LayerHierarchy::TraversalPath& path) {
+ const LayerHierarchy::TraversalPath& path,
+ bool newSnapshot) {
// Always update flags and visibility
ftl::Flags<RequestedLayerState::Changes> parentChanges = parentSnapshot.changes &
(RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Geometry |
RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Metadata |
RequestedLayerState::Changes::AffectsChildren);
snapshot.changes = parentChanges | requested.changes;
- snapshot.isHiddenByPolicyFromParent =
- parentSnapshot.isHiddenByPolicyFromParent || requested.isHiddenByPolicy();
+ snapshot.isHiddenByPolicyFromParent = parentSnapshot.isHiddenByPolicyFromParent ||
+ parentSnapshot.invalidTransform || requested.isHiddenByPolicy();
snapshot.contentDirty = requested.what & layer_state_t::CONTENT_DIRTY;
- if (snapshot.isHiddenByPolicyFromParent) {
- snapshot.isVisible = false;
- return;
- }
+ // TODO(b/238781169) scope down the changes to only buffer updates.
+ snapshot.hasReadyFrame =
+ (snapshot.contentDirty || requested.autoRefresh) && (requested.externalTexture);
+ // TODO(b/238781169) how is this used? ag/15523870
+ snapshot.sidebandStreamHasFrame = false;
+ updateSurfaceDamage(requested, snapshot.hasReadyFrame, args.forceFullDamage,
+ snapshot.surfaceDamage);
+ const bool forceUpdate = newSnapshot || args.forceUpdate ||
+ snapshot.changes.any(RequestedLayerState::Changes::Visibility |
+ RequestedLayerState::Changes::Created);
uint32_t displayRotationFlags =
getDisplayRotationFlags(args.displays, snapshot.outputFilter.layerStack);
- const bool forceUpdate = args.forceUpdate ||
- snapshot.changes.any(RequestedLayerState::Changes::Visibility |
- RequestedLayerState::Changes::Created);
+ // always update the buffer regardless of visibility
+ if (forceUpdate || requested.what & layer_state_t::BUFFER_CHANGES) {
+ snapshot.acquireFence =
+ (requested.externalTexture &&
+ requested.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged))
+ ? requested.bufferData->acquireFence
+ : Fence::NO_FENCE;
+ snapshot.buffer =
+ requested.externalTexture ? requested.externalTexture->getBuffer() : nullptr;
+ snapshot.bufferSize = requested.getBufferSize(displayRotationFlags);
+ snapshot.geomBufferSize = snapshot.bufferSize;
+ snapshot.croppedBufferSize = requested.getCroppedBufferSize(snapshot.bufferSize);
+ snapshot.dataspace = requested.dataspace;
+ snapshot.externalTexture = requested.externalTexture;
+ snapshot.frameNumber = (requested.bufferData) ? requested.bufferData->frameNumber : 0;
+ snapshot.geomBufferTransform = requested.bufferTransform;
+ snapshot.geomBufferUsesDisplayInverseTransform = requested.transformToDisplayInverse;
+ snapshot.geomContentCrop = requested.getBufferCrop();
+ snapshot.geomUsesSourceCrop = snapshot.hasBufferOrSidebandStream();
+ snapshot.hasProtectedContent = requested.externalTexture &&
+ requested.externalTexture->getUsage() & GRALLOC_USAGE_PROTECTED;
+ snapshot.isHdrY410 = requested.dataspace == ui::Dataspace::BT2020_ITU_PQ &&
+ requested.api == NATIVE_WINDOW_API_MEDIA &&
+ requested.bufferData->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102;
+ snapshot.sidebandStream = requested.sidebandStream;
+ snapshot.transparentRegionHint = requested.transparentRegion;
+ snapshot.color.rgb = requested.getColor().rgb;
+ }
+
+ if (snapshot.isHiddenByPolicyFromParent && !newSnapshot) {
+ if (forceUpdate ||
+ snapshot.changes.any(RequestedLayerState::Changes::Hierarchy |
+ RequestedLayerState::Changes::Geometry |
+ RequestedLayerState::Changes::Input)) {
+ updateInput(snapshot, requested, parentSnapshot, path, args);
+ }
+ return;
+ }
if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::AffectsChildren)) {
// If root layer, use the layer stack otherwise get the parent's layer stack.
@@ -567,6 +701,17 @@
snapshot.colorTransform = requested.colorTransform;
snapshot.colorTransformIsIdentity = !requested.hasColorTransform;
}
+ snapshot.gameMode = requested.metadata.has(gui::METADATA_GAME_MODE)
+ ? requested.gameMode
+ : parentSnapshot.gameMode;
+ snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() ||
+ (requested.requestedFrameRate.type ==
+ scheduler::LayerInfo::FrameRateCompatibility::NoVote))
+ ? requested.requestedFrameRate
+ : parentSnapshot.frameRate;
+ snapshot.fixedTransformHint = requested.fixedTransformHint != ui::Transform::ROT_INVALID
+ ? requested.fixedTransformHint
+ : parentSnapshot.fixedTransformHint;
}
if (forceUpdate || requested.changes.get() != 0) {
@@ -576,35 +721,11 @@
(requested.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque;
}
- if (forceUpdate || requested.what & layer_state_t::BUFFER_CHANGES) {
- snapshot.acquireFence =
- (requested.bufferData) ? requested.bufferData->acquireFence : Fence::NO_FENCE;
- snapshot.buffer =
- requested.externalTexture ? requested.externalTexture->getBuffer() : nullptr;
- snapshot.bufferSize = requested.getBufferSize(displayRotationFlags);
- snapshot.geomBufferSize = snapshot.bufferSize;
- snapshot.croppedBufferSize = requested.getCroppedBufferSize(snapshot.bufferSize);
- snapshot.dataspace = requested.dataspace;
- snapshot.externalTexture = requested.externalTexture;
- snapshot.frameNumber = (requested.bufferData) ? requested.bufferData->frameNumber : 0;
- snapshot.geomBufferTransform = requested.bufferTransform;
- snapshot.geomBufferUsesDisplayInverseTransform = requested.transformToDisplayInverse;
- snapshot.geomContentCrop = requested.getBufferCrop();
- snapshot.geomUsesSourceCrop = snapshot.hasBufferOrSidebandStream();
- snapshot.hasProtectedContent = requested.externalTexture &&
- requested.externalTexture->getUsage() & GRALLOC_USAGE_PROTECTED;
- snapshot.isHdrY410 = requested.dataspace == ui::Dataspace::BT2020_ITU_PQ &&
- requested.api == NATIVE_WINDOW_API_MEDIA &&
- requested.bufferData->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102;
- snapshot.sidebandStream = requested.sidebandStream;
- snapshot.surfaceDamage = requested.surfaceDamageRegion;
- snapshot.transparentRegionHint = requested.transparentRegion;
- }
-
if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::Content)) {
snapshot.color.rgb = requested.getColor().rgb;
snapshot.isColorspaceAgnostic = requested.colorSpaceAgnostic;
- snapshot.backgroundBlurRadius = static_cast<int>(requested.backgroundBlurRadius);
+ snapshot.backgroundBlurRadius =
+ args.supportsBlur ? static_cast<int>(requested.backgroundBlurRadius) : 0;
snapshot.blurRegions = requested.blurRegions;
snapshot.hdrMetadata = requested.hdrMetadata;
}
@@ -620,12 +741,7 @@
snapshot.changes.any(RequestedLayerState::Changes::Hierarchy |
RequestedLayerState::Changes::Geometry |
RequestedLayerState::Changes::Input)) {
- static frontend::DisplayInfo sDefaultInfo = {.isSecure = false};
- const std::optional<frontend::DisplayInfo> displayInfo =
- args.displays.get(snapshot.outputFilter.layerStack);
- bool noValidDisplay = !displayInfo.has_value();
- updateInput(snapshot, requested, parentSnapshot, displayInfo.value_or(sDefaultInfo),
- noValidDisplay, path);
+ updateInput(snapshot, requested, parentSnapshot, path, args);
}
// computed snapshot properties
@@ -636,12 +752,14 @@
}
snapshot.forceClientComposition = snapshot.isHdrY410 || snapshot.shadowSettings.length > 0 ||
requested.blurRegions.size() > 0 || snapshot.stretchEffect.hasEffect();
- snapshot.isVisible = snapshot.getIsVisible();
snapshot.isOpaque = snapshot.isContentOpaque() && !snapshot.roundedCorner.hasRoundedCorners() &&
snapshot.color.a == 1.f;
snapshot.blendMode = getBlendMode(snapshot, requested);
-
- ALOGV("%supdated [%d]%s changes parent:%s global:%s local:%s requested:%s %s from parent %s",
+ // TODO(b/238781169) pass this from flinger
+ // snapshot.fps;
+ // snapshot.metadata;
+ LLOGV(snapshot.sequence,
+ "%supdated [%d]%s changes parent:%s global:%s local:%s requested:%s %s from parent %s",
args.forceUpdate ? "Force " : "", requested.id, requested.name.c_str(),
parentSnapshot.changes.string().c_str(), snapshot.changes.string().c_str(),
requested.changes.string().c_str(), std::to_string(requested.what).c_str(),
@@ -694,12 +812,35 @@
snapshot.localTransform = requested.getTransform(displayRotationFlags);
snapshot.localTransformInverse = snapshot.localTransform.inverse();
snapshot.geomLayerTransform = parentSnapshot.geomLayerTransform * snapshot.localTransform;
+ const bool transformWasInvalid = snapshot.invalidTransform;
snapshot.invalidTransform = !LayerSnapshot::isTransformValid(snapshot.geomLayerTransform);
if (snapshot.invalidTransform) {
- ALOGW("Resetting transform for %s because it has an invalid transformation.",
- requested.getDebugStringShort().c_str());
+ auto& t = snapshot.geomLayerTransform;
+ auto& requestedT = requested.requestedTransform;
+ std::string transformDebug =
+ base::StringPrintf(" transform={%f,%f,%f,%f} requestedTransform={%f,%f,%f,%f}",
+ t.dsdx(), t.dsdy(), t.dtdx(), t.dtdy(), requestedT.dsdx(),
+ requestedT.dsdy(), requestedT.dtdx(), requestedT.dtdy());
+ std::string bufferDebug;
+ if (requested.externalTexture) {
+ auto unRotBuffer = requested.getUnrotatedBufferSize(displayRotationFlags);
+ auto& destFrame = requested.destinationFrame;
+ bufferDebug = base::StringPrintf(" buffer={%d,%d} displayRot=%d"
+ " destFrame={%d,%d,%d,%d} unRotBuffer={%d,%d}",
+ requested.externalTexture->getWidth(),
+ requested.externalTexture->getHeight(),
+ displayRotationFlags, destFrame.left, destFrame.top,
+ destFrame.right, destFrame.bottom,
+ unRotBuffer.getHeight(), unRotBuffer.getWidth());
+ }
+ ALOGW("Resetting transform for %s because it is invalid.%s%s",
+ snapshot.getDebugString().c_str(), transformDebug.c_str(), bufferDebug.c_str());
snapshot.geomLayerTransform.reset();
}
+ if (transformWasInvalid != snapshot.invalidTransform) {
+ // If transform is invalid, the layer will be hidden.
+ mResortSnapshots = true;
+ }
snapshot.geomInverseLayerTransform = snapshot.geomLayerTransform.inverse();
FloatRect parentBounds = parentSnapshot.geomLayerBounds;
@@ -711,12 +852,19 @@
}
snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(parentBounds);
snapshot.transformedBounds = snapshot.geomLayerTransform.transform(snapshot.geomLayerBounds);
+ const Rect geomLayerBoundsWithoutTransparentRegion =
+ RequestedLayerState::reduce(Rect(snapshot.geomLayerBounds),
+ requested.transparentRegion);
+ snapshot.transformedBoundsWithoutTransparentRegion =
+ snapshot.geomLayerTransform.transform(geomLayerBoundsWithoutTransparentRegion);
snapshot.parentTransform = parentSnapshot.geomLayerTransform;
// Subtract the transparent region and snap to the bounds
- Rect bounds =
+ const Rect bounds =
RequestedLayerState::reduce(snapshot.croppedBufferSize, requested.transparentRegion);
- snapshot.cursorFrame = snapshot.geomLayerTransform.transform(bounds);
+ if (requested.potentialCursor) {
+ snapshot.cursorFrame = snapshot.geomLayerTransform.transform(bounds);
+ }
// TODO(b/238781169) use dest vs src
snapshot.bufferNeedsFiltering = snapshot.externalTexture &&
@@ -749,15 +897,28 @@
void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot,
const RequestedLayerState& requested,
const LayerSnapshot& parentSnapshot,
- const frontend::DisplayInfo& displayInfo,
- bool noValidDisplay,
- const LayerHierarchy::TraversalPath& path) {
+ const LayerHierarchy::TraversalPath& path,
+ const Args& args) {
+ if (requested.windowInfoHandle) {
+ snapshot.inputInfo = *requested.windowInfoHandle->getInfo();
+ } else {
+ snapshot.inputInfo = {};
+ }
snapshot.inputInfo.displayId = static_cast<int32_t>(snapshot.outputFilter.layerStack.id);
- if (!requested.hasInputInfo()) {
- snapshot.inputInfo.inputConfig = gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL;
+
+ if (!needsInputInfo(snapshot, requested)) {
return;
}
+ static frontend::DisplayInfo sDefaultInfo = {.isSecure = false};
+ const std::optional<frontend::DisplayInfo> displayInfoOpt =
+ args.displays.get(snapshot.outputFilter.layerStack);
+ bool noValidDisplay = !displayInfoOpt.has_value();
+ auto displayInfo = displayInfoOpt.value_or(sDefaultInfo);
+
+ if (!requested.windowInfoHandle) {
+ snapshot.inputInfo.inputConfig = gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL;
+ }
fillInputFrameInfo(snapshot.inputInfo, displayInfo.transform, snapshot);
if (noValidDisplay) {
@@ -766,17 +927,6 @@
snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::NOT_TOUCHABLE;
}
- // For compatibility reasons we let layers which can receive input
- // receive input before they have actually submitted a buffer. Because
- // of this we use canReceiveInput instead of isVisible to check the
- // policy-visibility, ignoring the buffer state. However for layers with
- // hasInputInfo()==false we can use the real visibility state.
- // We are just using these layers for occlusion detection in
- // InputDispatcher, and obviously if they aren't visible they can't occlude
- // anything.
- const bool visible = requested.hasInputInfo() ? snapshot.canReceiveInput() : snapshot.isVisible;
- snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible);
-
snapshot.inputInfo.alpha = snapshot.color.a;
snapshot.inputInfo.touchOcclusionMode = parentSnapshot.inputInfo.touchOcclusionMode;
if (requested.dropInputMode == gui::DropInputMode::ALL ||
@@ -830,4 +980,28 @@
return mSnapshots;
}
+void LayerSnapshotBuilder::forEachVisibleSnapshot(const ConstVisitor& visitor) const {
+ for (int i = 0; i < mNumInterestingSnapshots; i++) {
+ LayerSnapshot& snapshot = *mSnapshots[(size_t)i];
+ if (!snapshot.isVisible) continue;
+ visitor(snapshot);
+ }
+}
+
+void LayerSnapshotBuilder::forEachVisibleSnapshot(const Visitor& visitor) {
+ for (int i = 0; i < mNumInterestingSnapshots; i++) {
+ std::unique_ptr<LayerSnapshot>& snapshot = mSnapshots.at((size_t)i);
+ if (!snapshot->isVisible) continue;
+ visitor(snapshot);
+ }
+}
+
+void LayerSnapshotBuilder::forEachInputSnapshot(const ConstVisitor& visitor) const {
+ for (int i = mNumInterestingSnapshots - 1; i >= 0; i--) {
+ LayerSnapshot& snapshot = *mSnapshots[(size_t)i];
+ if (!snapshot.hasInputInfo()) continue;
+ visitor(snapshot);
+ }
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
index 33b250c..abb7e66 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
@@ -44,6 +44,8 @@
// Set to true if there were display changes since last update.
bool displayChanges = false;
const renderengine::ShadowSettings& globalShadowSettings;
+ bool supportsBlur = true;
+ bool forceFullDamage = false;
};
LayerSnapshotBuilder();
@@ -56,10 +58,22 @@
// change flags.
void update(const Args&);
std::vector<std::unique_ptr<LayerSnapshot>>& getSnapshots();
+ LayerSnapshot* getSnapshot(uint32_t layerId) const;
+
+ typedef std::function<void(const LayerSnapshot& snapshot)> ConstVisitor;
+
+ // Visit each visible snapshot in z-order
+ void forEachVisibleSnapshot(const ConstVisitor& visitor) const;
+
+ typedef std::function<void(std::unique_ptr<LayerSnapshot>& snapshot)> Visitor;
+ // Visit each visible snapshot in z-order and move the snapshot if needed
+ void forEachVisibleSnapshot(const Visitor& visitor);
+
+ // Visit each snapshot interesting to input reverse z-order
+ void forEachInputSnapshot(const ConstVisitor& visitor) const;
private:
friend class LayerSnapshotTest;
- LayerSnapshot* getSnapshot(uint32_t layerId) const;
LayerSnapshot* getSnapshot(const LayerHierarchy::TraversalPath& id) const;
static LayerSnapshot getRootSnapshot();
@@ -69,28 +83,29 @@
void updateSnapshots(const Args& args);
- void updateSnapshotsInHierarchy(const Args&, const LayerHierarchy& hierarchy,
- LayerHierarchy::TraversalPath& traversalPath,
- const LayerSnapshot& parentSnapshot);
- void updateSnapshot(LayerSnapshot& snapshot, const Args& args, const RequestedLayerState&,
- const LayerSnapshot& parentSnapshot,
- const LayerHierarchy::TraversalPath& path);
+ const LayerSnapshot& updateSnapshotsInHierarchy(const Args&, const LayerHierarchy& hierarchy,
+ LayerHierarchy::TraversalPath& traversalPath,
+ const LayerSnapshot& parentSnapshot);
+ void updateSnapshot(LayerSnapshot&, const Args&, const RequestedLayerState&,
+ const LayerSnapshot& parentSnapshot, const LayerHierarchy::TraversalPath&,
+ bool newSnapshot);
static void updateRelativeState(LayerSnapshot& snapshot, const LayerSnapshot& parentSnapshot,
bool parentIsRelative, const Args& args);
static void resetRelativeState(LayerSnapshot& snapshot);
static void updateRoundedCorner(LayerSnapshot& snapshot, const RequestedLayerState& layerState,
const LayerSnapshot& parentSnapshot);
- static void updateLayerBounds(LayerSnapshot& snapshot, const RequestedLayerState& layerState,
- const LayerSnapshot& parentSnapshot,
- uint32_t displayRotationFlags);
+ void updateLayerBounds(LayerSnapshot& snapshot, const RequestedLayerState& layerState,
+ const LayerSnapshot& parentSnapshot, uint32_t displayRotationFlags);
static void updateShadows(LayerSnapshot& snapshot, const RequestedLayerState& requested,
const renderengine::ShadowSettings& globalShadowSettings);
void updateInput(LayerSnapshot& snapshot, const RequestedLayerState& requested,
- const LayerSnapshot& parentSnapshot, const frontend::DisplayInfo& displayInfo,
- bool noValidDisplay, const LayerHierarchy::TraversalPath& path);
+ const LayerSnapshot& parentSnapshot, const LayerHierarchy::TraversalPath& path,
+ const Args& args);
void sortSnapshotsByZ(const Args& args);
- LayerSnapshot* getOrCreateSnapshot(const LayerHierarchy::TraversalPath& id,
- const RequestedLayerState& layer);
+ LayerSnapshot* createSnapshot(const LayerHierarchy::TraversalPath& id,
+ const RequestedLayerState& layer);
+ void updateChildState(LayerSnapshot& snapshot, const LayerSnapshot& childSnapshot,
+ const Args& args);
struct TraversalPathHash {
std::size_t operator()(const LayerHierarchy::TraversalPath& key) const {
@@ -105,6 +120,8 @@
mIdToSnapshot;
std::vector<std::unique_ptr<LayerSnapshot>> mSnapshots;
LayerSnapshot mRootSnapshot;
+ bool mResortSnapshots = false;
+ int mNumInterestingSnapshots = 0;
};
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index dcc16e8..39bf07a 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -14,16 +14,18 @@
* limitations under the License.
*/
-#include "FrontEnd/LayerCreationArgs.h"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#undef LOG_TAG
#define LOG_TAG "RequestedLayerState"
+#include <log/log.h>
#include <private/android_filesystem_config.h>
#include <sys/types.h>
#include "Layer.h"
+#include "LayerCreationArgs.h"
#include "LayerHandle.h"
+#include "LayerLog.h"
#include "RequestedLayerState.h"
namespace android::surfaceflinger::frontend {
@@ -47,7 +49,7 @@
RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args)
: id(args.sequence),
- name(args.name),
+ name(args.name + "#" + std::to_string(args.sequence)),
canBeRoot(args.addToRoot),
layerCreationFlags(args.flags),
textureName(args.textureName),
@@ -59,6 +61,9 @@
changes |= RequestedLayerState::Changes::Metadata;
handleAlive = true;
parentId = LayerHandle::getLayerId(args.parentHandle.promote());
+ if (args.parentHandle != nullptr) {
+ canBeRoot = false;
+ }
mirrorId = LayerHandle::getLayerId(args.mirrorLayerHandle.promote());
if (mirrorId != UNASSIGNED_LAYER_ID) {
changes |= RequestedLayerState::Changes::Mirror;
@@ -83,6 +88,7 @@
} else {
color.rgb = {0.0_hf, 0.0_hf, 0.0_hf};
}
+ LLOGV(layerId, "Created %s flags=%d", getDebugString().c_str(), flags);
color.a = 1.0f;
crop.makeInvalid();
@@ -114,11 +120,14 @@
defaultFrameRateCompatibility =
static_cast<int8_t>(scheduler::LayerInfo::FrameRateCompatibility::Default);
dataspace = ui::Dataspace::V0_SRGB;
+ gameMode = gui::GameMode::Unsupported;
+ requestedFrameRate = {};
}
void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerState) {
- bool oldFlags = flags;
- Rect oldBufferSize = getBufferSize(0);
+ const uint32_t oldFlags = flags;
+ const half oldAlpha = color.a;
+ const bool hadBufferOrSideStream = hasValidBuffer() || sidebandStream != nullptr;
const layer_state_t& clientState = resolvedComposerState.state;
uint64_t clientChanges = what | layer_state_t::diff(clientState);
@@ -127,14 +136,28 @@
if (clientState.what & layer_state_t::eFlagsChanged) {
if ((oldFlags ^ flags) & layer_state_t::eLayerHidden) {
- changes |= RequestedLayerState::Changes::Visibility;
+ changes |= RequestedLayerState::Changes::Visibility |
+ RequestedLayerState::Changes::VisibleRegion;
}
if ((oldFlags ^ flags) & layer_state_t::eIgnoreDestinationFrame) {
changes |= RequestedLayerState::Changes::Geometry;
}
}
- if (clientState.what & layer_state_t::eBufferChanged && oldBufferSize != getBufferSize(0)) {
- changes |= RequestedLayerState::Changes::Geometry;
+ if (clientState.what &
+ (layer_state_t::eBufferChanged | layer_state_t::eSidebandStreamChanged)) {
+ const bool hasBufferOrSideStream = hasValidBuffer() || sidebandStream != nullptr;
+ if (hadBufferOrSideStream != hasBufferOrSideStream) {
+ changes |= RequestedLayerState::Changes::Geometry |
+ RequestedLayerState::Changes::VisibleRegion |
+ RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Input |
+ RequestedLayerState::Changes::Buffer;
+ }
+ }
+ if (what & (layer_state_t::eAlphaChanged)) {
+ if (oldAlpha == 0 || color.a == 0) {
+ changes |= RequestedLayerState::Changes::Visibility |
+ RequestedLayerState::Changes::VisibleRegion;
+ }
}
if (clientChanges & layer_state_t::HIERARCHY_CHANGES)
changes |= RequestedLayerState::Changes::Hierarchy;
@@ -144,7 +167,10 @@
changes |= RequestedLayerState::Changes::Geometry;
if (clientChanges & layer_state_t::AFFECTS_CHILDREN)
changes |= RequestedLayerState::Changes::AffectsChildren;
-
+ if (clientChanges & layer_state_t::INPUT_CHANGES)
+ changes |= RequestedLayerState::Changes::Input;
+ if (clientChanges & layer_state_t::VISIBLE_REGION_CHANGES)
+ changes |= RequestedLayerState::Changes::VisibleRegion;
if (clientState.what & layer_state_t::eColorTransformChanged) {
static const mat4 identityMatrix = mat4();
hasColorTransform = colorTransform != identityMatrix;
@@ -183,7 +209,6 @@
wp<IBinder>& touchableRegionCropHandle =
windowInfoHandle->editInfo()->touchableRegionCropHandle;
touchCropId = LayerHandle::getLayerId(touchableRegionCropHandle.promote());
- changes |= RequestedLayerState::Changes::Input;
touchableRegionCropHandle.clear();
}
if (clientState.what & layer_state_t::eStretchChanged) {
@@ -205,6 +230,27 @@
if (clientState.what & layer_state_t::eMatrixChanged) {
requestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
}
+ if (clientState.what & layer_state_t::eMetadataChanged) {
+ const int32_t requestedGameMode =
+ clientState.metadata.getInt32(gui::METADATA_GAME_MODE, -1);
+ if (requestedGameMode != -1) {
+ // The transaction will be received on the Task layer and needs to be applied to all
+ // child layers.
+ if (static_cast<int32_t>(gameMode) != requestedGameMode) {
+ gameMode = static_cast<gui::GameMode>(requestedGameMode);
+ changes |= RequestedLayerState::Changes::AffectsChildren;
+ }
+ }
+ }
+ if (clientState.what & layer_state_t::eFrameRateChanged) {
+ const auto compatibility =
+ Layer::FrameRate::convertCompatibility(clientState.frameRateCompatibility);
+ const auto strategy = Layer::FrameRate::convertChangeFrameRateStrategy(
+ clientState.changeFrameRateStrategy);
+ requestedFrameRate =
+ Layer::FrameRate(Fps::fromValue(clientState.frameRate), compatibility, strategy);
+ changes |= RequestedLayerState::Changes::FrameRate;
+ }
}
ui::Size RequestedLayerState::getUnrotatedBufferSize(uint32_t displayRotationFlags) const {
@@ -368,7 +414,8 @@
// If the relative parentid is unassigned, the layer will be considered relative but won't be
// reachable.
bool RequestedLayerState::hasValidRelativeParent() const {
- return isRelativeOf && parentId != relativeParentId;
+ return isRelativeOf &&
+ (parentId != relativeParentId || relativeParentId == UNASSIGNED_LAYER_ID);
}
bool RequestedLayerState::hasInputInfo() const {
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
index 95240d0..3a16531 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
@@ -20,6 +20,7 @@
#include <ftl/flags.h>
#include <gui/LayerState.h>
#include <renderengine/ExternalTexture.h>
+#include "Scheduler/LayerInfo.h"
#include "LayerCreationArgs.h"
#include "TransactionState.h"
@@ -48,6 +49,9 @@
Metadata = 1u << 10,
Visibility = 1u << 11,
AffectsChildren = 1u << 12,
+ FrameRate = 1u << 13,
+ VisibleRegion = 1u << 14,
+ Buffer = 1u << 15,
};
static Rect reduce(const Rect& win, const Region& exclude);
RequestedLayerState(const LayerCreationArgs&);
@@ -91,6 +95,8 @@
ui::Transform requestedTransform;
std::shared_ptr<FenceTime> acquireFenceTime;
std::shared_ptr<renderengine::ExternalTexture> externalTexture;
+ gui::GameMode gameMode;
+ scheduler::LayerInfo::FrameRate requestedFrameRate;
// book keeping states
bool handleAlive = true;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 0179d62..ba1d2c6 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -475,7 +475,8 @@
snapshot->geomLayerTransform = getTransform();
snapshot->geomInverseLayerTransform = snapshot->geomLayerTransform.inverse();
snapshot->transparentRegionHint = getActiveTransparentRegion(drawingState);
- snapshot->localTransformInverse = getActiveTransform(drawingState).inverse();
+ snapshot->localTransform = getActiveTransform(drawingState);
+ snapshot->localTransformInverse = snapshot->localTransform.inverse();
snapshot->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
snapshot->alpha = alpha;
snapshot->backgroundBlurRadius = drawingState.backgroundBlurRadius;
@@ -2595,6 +2596,8 @@
mDrawingState = from->mDrawingState;
// Skip callback info since they are not applicable for cloned layers.
mDrawingState.releaseBufferListener = nullptr;
+ // TODO (b/238781169) currently broken for mirror layers because we do not
+ // track release fences for mirror layers composed on other displays
mDrawingState.callbackHandles = {};
}
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
index 33c9440..783df28 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
@@ -562,4 +562,83 @@
hierarchyBuilder.getHierarchy().traverseInZOrder(checkTraversalPathIdVisitor);
}
+TEST_F(LayerHierarchyTest, zorderRespectsLayerSequenceId) {
+ // remove default hierarchy
+ mLifecycleManager = LayerLifecycleManager();
+ createRootLayer(1);
+ createRootLayer(2);
+ createRootLayer(4);
+ createRootLayer(5);
+ createLayer(11, 1);
+ createLayer(51, 5);
+ createLayer(53, 5);
+
+ mLifecycleManager.commitChanges();
+ LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers());
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+ std::vector<uint32_t> expectedTraversalPath = {1, 11, 2, 4, 5, 51, 53};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+
+ EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+ expectedTraversalPath = {};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
+
+ // A new layer is added with a smaller sequence id. Make sure its sorted correctly. While
+ // sequence ids are always incremented, this scenario can happen when a layer is reparented.
+ createRootLayer(3);
+ createLayer(52, 5);
+
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+ expectedTraversalPath = {1, 11, 2, 3, 4, 5, 51, 52, 53};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+ EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+ expectedTraversalPath = {};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
+}
+
+TEST_F(LayerHierarchyTest, zorderRespectsLayerZ) {
+ // remove default hierarchy
+ mLifecycleManager = LayerLifecycleManager();
+ createRootLayer(1);
+ createLayer(11, 1);
+ createLayer(12, 1);
+ createLayer(13, 1);
+ setZ(11, -1);
+ setZ(12, 2);
+ setZ(13, 1);
+
+ mLifecycleManager.commitChanges();
+ LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers());
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+ std::vector<uint32_t> expectedTraversalPath = {1, 11, 13, 12};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+
+ expectedTraversalPath = {11, 1, 13, 12};
+ EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+ expectedTraversalPath = {};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
+}
+
+TEST_F(LayerHierarchyTest, zorderRespectsLayerStack) {
+ // remove default hierarchy
+ mLifecycleManager = LayerLifecycleManager();
+ createRootLayer(1);
+ createRootLayer(2);
+ createLayer(11, 1);
+ createLayer(21, 2);
+ setLayerStack(1, 20);
+ setLayerStack(2, 10);
+
+ mLifecycleManager.commitChanges();
+ LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers());
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+ std::vector<uint32_t> expectedTraversalPath = {1, 11, 2, 21};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+
+ expectedTraversalPath = {1, 11, 2, 21};
+ EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+ expectedTraversalPath = {};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index 08727f2..1a82232 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -245,6 +245,18 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setLayerStack(uint32_t id, int32_t layerStack) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eLayerStackChanged;
+ transactions.back().states.front().state.surface = mHandles[id];
+ transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().state.layerStack = ui::LayerStack::fromValue(layerStack);
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
LayerLifecycleManager mLifecycleManager;
std::unordered_map<uint32_t, sp<LayerHandle>> mHandles;
};
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 2441c06..e124342 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -38,6 +38,9 @@
namespace android::surfaceflinger::frontend {
+using ftl::Flags;
+using namespace ftl::flag_operators;
+
// To run test:
/**
mp :libsurfaceflinger_unittest && adb sync; adb shell \
@@ -88,14 +91,11 @@
ASSERT_TRUE(expectedBuilder.getSnapshots().size() > 0);
ASSERT_TRUE(actualBuilder.getSnapshots().size() > 0);
- std::vector<std::unique_ptr<LayerSnapshot>>& snapshots = actualBuilder.getSnapshots();
std::vector<uint32_t> actualVisibleLayerIdsInZOrder;
- for (auto& snapshot : snapshots) {
- if (!snapshot->isVisible) {
- break;
- }
- actualVisibleLayerIdsInZOrder.push_back(snapshot->path.id);
- }
+ actualBuilder.forEachVisibleSnapshot(
+ [&actualVisibleLayerIdsInZOrder](const LayerSnapshot& snapshot) {
+ actualVisibleLayerIdsInZOrder.push_back(snapshot.path.id);
+ });
EXPECT_EQ(expectedVisibleLayerIdsInZOrder, actualVisibleLayerIdsInZOrder);
}
@@ -103,7 +103,6 @@
LayerHierarchyBuilder mHierarchyBuilder{{}};
LayerSnapshotBuilder mSnapshotBuilder;
- std::unordered_map<uint32_t, sp<LayerHandle>> mHandles;
display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> mFrontEndDisplayInfos;
renderengine::ShadowSettings globalShadowSettings;
static const std::vector<uint32_t> STARTING_ZORDER;
@@ -257,4 +256,54 @@
EXPECT_EQ(getSnapshot(1)->changes, RequestedLayerState::Changes::Content);
}
+TEST_F(LayerSnapshotTest, GameMode) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().state.what = layer_state_t::eMetadataChanged;
+ transactions.back().states.front().state.metadata = LayerMetadata();
+ transactions.back().states.front().state.metadata.setInt32(METADATA_GAME_MODE, 42);
+ transactions.back().states.front().state.surface = mHandles[1];
+ transactions.back().states.front().state.layerId = static_cast<int32_t>(1);
+ mLifecycleManager.applyTransactions(transactions);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(static_cast<int32_t>(getSnapshot(1)->gameMode), 42);
+ EXPECT_EQ(static_cast<int32_t>(getSnapshot(11)->gameMode), 42);
+}
+
+TEST_F(LayerSnapshotTest, NoLayerVoteForParentWithChildVotes) {
+ // ROOT
+ // ├── 1
+ // │ ├── 11 (frame rate set)
+ // │ │ └── 111
+ // │ ├── 12
+ // │ │ ├── 121
+ // │ │ └── 122
+ // │ │ └── 1221
+ // │ └── 13
+ // └── 2
+
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().state.what = layer_state_t::eFrameRateChanged;
+ transactions.back().states.front().state.frameRate = 90.0;
+ transactions.back().states.front().state.frameRateCompatibility =
+ ANATIVEWINDOW_FRAME_RATE_EXACT;
+ transactions.back().states.front().state.changeFrameRateStrategy =
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS;
+ transactions.back().states.front().state.surface = mHandles[11];
+ transactions.back().states.front().state.layerId = static_cast<int32_t>(11);
+ mLifecycleManager.applyTransactions(transactions);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_EQ(getSnapshot(11)->frameRate.rate.getIntValue(), 90);
+ EXPECT_EQ(getSnapshot(11)->frameRate.type, scheduler::LayerInfo::FrameRateCompatibility::Exact);
+ EXPECT_EQ(getSnapshot(111)->frameRate.rate.getIntValue(), 90);
+ EXPECT_EQ(getSnapshot(111)->frameRate.type,
+ scheduler::LayerInfo::FrameRateCompatibility::Exact);
+ EXPECT_EQ(getSnapshot(1)->frameRate.rate.getIntValue(), 0);
+ EXPECT_EQ(getSnapshot(1)->frameRate.type, scheduler::LayerInfo::FrameRateCompatibility::NoVote);
+}
+
} // namespace android::surfaceflinger::frontend