diff options
16 files changed, 624 insertions, 170 deletions
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 555277543e..70c9daf42b 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -248,9 +248,9 @@ struct layer_state_t { layer_state_t::eBackgroundBlurRadiusChanged | layer_state_t::eBackgroundColorChanged | layer_state_t::eBlurRegionsChanged | layer_state_t::eColorChanged | layer_state_t::eColorSpaceAgnosticChanged | layer_state_t::eColorTransformChanged | - layer_state_t::eCornerRadiusChanged | layer_state_t::eHdrMetadataChanged | - layer_state_t::eRenderBorderChanged | layer_state_t::eShadowRadiusChanged | - layer_state_t::eStretchChanged; + layer_state_t::eCornerRadiusChanged | layer_state_t::eDimmingEnabledChanged | + layer_state_t::eHdrMetadataChanged | layer_state_t::eRenderBorderChanged | + layer_state_t::eShadowRadiusChanged | layer_state_t::eStretchChanged; // Changes which invalidates the layer's visible region in CE. static constexpr uint64_t CONTENT_DIRTY = layer_state_t::CONTENT_CHANGES | @@ -261,7 +261,17 @@ struct layer_state_t { layer_state_t::HIERARCHY_CHANGES | layer_state_t::eAlphaChanged | layer_state_t::eColorTransformChanged | layer_state_t::eCornerRadiusChanged | layer_state_t::eFlagsChanged | layer_state_t::eLayerStackChanged | - layer_state_t::eTrustedOverlayChanged; + layer_state_t::eTrustedOverlayChanged | layer_state_t::eFrameRateChanged | + layer_state_t::eFixedTransformHintChanged; + + // Changes affecting data sent to input. + static constexpr uint64_t INPUT_CHANGES = layer_state_t::GEOMETRY_CHANGES | + layer_state_t::HIERARCHY_CHANGES | layer_state_t::eInputInfoChanged | + layer_state_t::eDropInputModeChanged | layer_state_t::eTrustedOverlayChanged; + + // Changes that affect the visible region on a display. + static constexpr uint64_t VISIBLE_REGION_CHANGES = + layer_state_t::GEOMETRY_CHANGES | layer_state_t::HIERARCHY_CHANGES; bool hasValidBuffer() const; void sanitize(int32_t permissions); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 2b6a51979f..c61f7d8e55 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -166,7 +166,8 @@ auto DisplayDevice::getFrontEndInfo() const -> frontend::DisplayInfo { .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 0c7b24a2c4..6b9d7a2f5c 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 @@ struct DisplayInfo { // 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 514a642bdc..678d36b5cf 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp @@ -28,8 +28,8 @@ auto layerZCompare = [](const std::pair<LayerHierarchy*, LayerHierarchy::Variant 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 @@ void LayerHierarchy::traverseInZOrder(const Visitor& visitor, 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 8cdc24062b..ca8d301879 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h @@ -41,11 +41,13 @@ class LayerHierarchyBuilder; // 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 0000000000..47e1e30c48 --- /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 d483a99824..3a0540c659 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -61,7 +61,7 @@ bool LayerSnapshot::isOpaqueFormat(PixelFormat format) { } bool LayerSnapshot::hasBufferOrSidebandStream() const { - return ((sidebandStream != nullptr) || (buffer != nullptr)); + return ((sidebandStream != nullptr) || (externalTexture != nullptr)); } bool LayerSnapshot::drawShadows() const { @@ -99,7 +99,7 @@ bool LayerSnapshot::isContentOpaque() const { // 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::isContentOpaque() const { } 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 @@ bool LayerSnapshot::getIsVisible() const { } std::string LayerSnapshot::getIsVisibleReason() const { - if (!hasSomethingToDraw()) { - return "!hasSomethingToDraw"; - } - - if (isHiddenByPolicy()) { - return "isHiddenByPolicy"; - } - - if (color.a > 0.0f || hasBlur()) { - return ""; - } - - return "alpha = 0 and !hasBlur"; + // 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"; + + // 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 @@ bool LayerSnapshot::isTransformValid(const ui::Transform& t) { 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 d14bd3ae8b..4512ade977 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 RoundedCornerState { } }; +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 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { bool layerOpaqueFlagSet; RoundedCornerState roundedCorner; FloatRect transformedBounds; + Rect transformedBoundsWithoutTransparentRegion; renderengine::ShadowSettings shadowSettings; bool premultipliedAlpha; bool isHdrY410; @@ -75,6 +81,10 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { 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 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { 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 bff12d7b5a..40dffb9706 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 @@ auto getBlendMode(const LayerSnapshot& snapshot, const RequestedLayerState& requ 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 @@ LayerSnapshot LayerSnapshotBuilder::getRootSnapshot() { 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 @@ LayerSnapshotBuilder::LayerSnapshotBuilder(Args args) : LayerSnapshotBuilder() { } 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 @@ bool LayerSnapshotBuilder::tryFastUpdate(const Args& args) { // 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 @@ bool LayerSnapshotBuilder::tryFastUpdate(const Args& args) { 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 @@ void LayerSnapshotBuilder::updateSnapshots(const Args& args) { } sortSnapshotsByZ(args); - mRootSnapshot.changes.clear(); + clearChanges(mRootSnapshot); // Destroy unreachable snapshots if (args.layerLifecycleManager.getDestroyedLayers().empty()) { @@ -372,6 +433,7 @@ void LayerSnapshotBuilder::updateSnapshots(const Args& args) { } 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 @@ void LayerSnapshotBuilder::update(const Args& args) { 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 @@ void LayerSnapshotBuilder::updateSnapshotsInHierarchy(const Args& args, 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 @@ LayerSnapshot* LayerSnapshotBuilder::getSnapshot(const LayerHierarchy::Traversal 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 @@ void LayerSnapshotBuilder::sortSnapshotsByZ(const Args& args) { return; } + mResortSnapshots = false; + size_t globalZ = 0; args.root.traverseInZOrder( [this, &globalZ](const LayerHierarchy&, @@ -467,7 +524,8 @@ void LayerSnapshotBuilder::sortSnapshotsByZ(const Args& args) { 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 @@ void LayerSnapshotBuilder::sortSnapshotsByZ(const Args& args) { 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 @@ void LayerSnapshotBuilder::updateRelativeState(LayerSnapshot& snapshot, 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 @@ void LayerSnapshotBuilder::updateRelativeState(LayerSnapshot& snapshot, 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 @@ uint32_t getDisplayRotationFlags( 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 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a 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 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a (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 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a 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 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a } 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 @@ void LayerSnapshotBuilder::updateLayerBounds(LayerSnapshot& snapshot, 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 @@ void LayerSnapshotBuilder::updateLayerBounds(LayerSnapshot& snapshot, } 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::updateShadows(LayerSnapshot& snapshot, 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 @@ void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot, 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 @@ std::vector<std::unique_ptr<LayerSnapshot>>& LayerSnapshotBuilder::getSnapshots( 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 33b250c793..abb7e668c3 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h @@ -44,6 +44,8 @@ public: // 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 @@ public: // 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 @@ private: 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 @@ private: 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 dcc16e8db7..39bf07abd2 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 @@ std::string layerIdToString(uint32_t layerId) { 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 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) 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 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) } 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 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) 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 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta 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 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta 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 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta 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 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta 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 @@ Rect RequestedLayerState::reduce(const Rect& win, const Region& exclude) { // 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 95240d0682..3a16531d80 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 @@ struct RequestedLayerState : layer_state_t { 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 @@ struct RequestedLayerState : layer_state_t { 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 df76ed02c7..539f2fe353 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -566,7 +566,8 @@ void Layer::prepareBasicGeometryCompositionState() { 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; @@ -2686,6 +2687,8 @@ void Layer::cloneDrawingState(const Layer* from) { 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 33c94400d6..783df2821b 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp @@ -562,4 +562,83 @@ TEST_F(LayerHierarchyTest, traversalPathId) { 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 08727f2c17..1a822329bd 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -245,6 +245,18 @@ protected: 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 2441c065c0..e124342edc 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 @@ protected: 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 @@ protected: 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 @@ TEST_F(LayerSnapshotTest, FastPathSetsChangeFlagToContent) { 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 |