diff options
author | 2025-02-05 11:11:50 -0800 | |
---|---|---|
committer | 2025-02-05 11:11:50 -0800 | |
commit | ad9d51479938dba2b99df5fbd069dde9ee53bf49 (patch) | |
tree | daec36cec518e18982059913c96ec7ee3fc93f2f | |
parent | 01e3f8a348b379917f331d9b8ad2611e13b42928 (diff) |
Demarcate cached sets in composition summary
Previously, the composition summary indicated that HWC was compositing
more layers than it actually was.
Example when youtube video open and playing in a free form window
Before: bbrrrRrbbb
After: [b:brr]r[R:rbbb]
So there are 2 cached sets and 1 uncached set. One cached set and one uncached layer is composited by HWC, the other cached set is composed by the GPU.
Bug: 391428079
Flag: EXEMPT log only update
Test: Capture perfetto trace and confirm layers are skipped and overridden as expected
Change-Id: I4ffda43f5248ef8bb690cdaca0eeca7ffac3d997
9 files changed, 101 insertions, 37 deletions
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index e876693498..780758e2a3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -19,6 +19,7 @@ #include <optional> #include <ostream> #include <unordered_set> +#include "aidl/android/hardware/graphics/composer3/Composition.h" #include "ui/LayerStack.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues @@ -36,10 +37,6 @@ #include <utils/RefBase.h> #include <utils/Timers.h> -namespace aidl::android::hardware::graphics::composer3 { -enum class Composition; -} - namespace android { class Fence; @@ -182,10 +179,27 @@ public: // Whether the layer should be rendered with rounded corners. virtual bool hasRoundedCorners() const = 0; virtual void setWasClientComposed(const sp<Fence>&) {} - virtual void setHwcCompositionType( - aidl::android::hardware::graphics::composer3::Composition) = 0; - virtual aidl::android::hardware::graphics::composer3::Composition getHwcCompositionType() - const = 0; + + // These fields are all copied from the last written HWC state. + // This state is only used for debugging purposes. + struct HwcLayerDebugState { + aidl::android::hardware::graphics::composer3::Composition lastCompositionType = + aidl::android::hardware::graphics::composer3::Composition::INVALID; + // Corresponds to passing an alpha of 0 to HWC2::Layer::setPlaneAlpha. + bool wasSkipped = false; + + // Indicates whether the compositionengine::OutputLayer had properties overwritten. + // Not directly passed to HWC. + bool wasOverridden = false; + + // Corresponds to the GraphicBuffer ID of the buffer passed to HWC2::Layer::setBuffer. + // This buffer corresponds to a CachedSet that the LayerFE was flattened to. + uint64_t overrideBufferId = 0; + }; + + // Used for debugging purposes, e.g. perfetto tracing, dumpsys. + virtual void setLastHwcState(const LayerFE::HwcLayerDebugState &hwcState) = 0; + virtual const HwcLayerDebugState &getLastHwcState() const = 0; virtual const gui::LayerMetadata* getMetadata() const = 0; virtual const gui::LayerMetadata* getRelativeMetadata() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index 7744b8bb99..d2a5a2066c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -59,9 +59,9 @@ public: MOCK_CONST_METHOD0(getMetadata, gui::LayerMetadata*()); MOCK_CONST_METHOD0(getRelativeMetadata, gui::LayerMetadata*()); MOCK_METHOD0(onPictureProfileCommitted, void()); - MOCK_METHOD(void, setHwcCompositionType, - (aidl::android::hardware::graphics::composer3::Composition), (override)); - MOCK_METHOD(aidl::android::hardware::graphics::composer3::Composition, getHwcCompositionType, + MOCK_METHOD(void, setLastHwcState, + (const HwcLayerDebugState&), (override)); + MOCK_METHOD(const HwcLayerDebugState&, getLastHwcState, (), (const, override)); }; diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 9b66f01789..9d67122f2e 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -502,6 +502,15 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t editState().hwc->stateOverridden = isOverridden; editState().hwc->layerSkipped = skipLayer; + + + // Save the final HWC state for debugging purposes, e.g. perfetto tracing, dumpsys. + getLayerFE().setLastHwcState({.lastCompositionType = editState().hwc->hwcCompositionType, + .wasSkipped = skipLayer, + .wasOverridden = isOverridden, + .overrideBufferId = editState().overrideInfo.buffer + ? editState().overrideInfo.buffer.get()->getId() + : 0}); } void OutputLayer::writeOutputDependentGeometryStateToHWC(HWC2::Layer* hwcLayer, @@ -867,7 +876,6 @@ void OutputLayer::writeCompositionTypeToHWC(HWC2::Layer* hwcLayer, if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType || (outputDependentState.hwc->layerSkipped && !skipLayer)) { outputDependentState.hwc->hwcCompositionType = requestedCompositionType; - getLayerFE().setHwcCompositionType(requestedCompositionType); if (auto error = hwcLayer->setCompositionType(requestedCompositionType); error != hal::Error::NONE) { @@ -965,7 +973,13 @@ void OutputLayer::applyDeviceCompositionTypeChange(Composition compositionType) } hwcState.hwcCompositionType = compositionType; - getLayerFE().setHwcCompositionType(compositionType); + + getLayerFE().setLastHwcState({.lastCompositionType = hwcState.hwcCompositionType, + .wasSkipped = hwcState.layerSkipped, + .wasOverridden = hwcState.stateOverridden, + .overrideBufferId = state.overrideInfo.buffer + ? state.overrideInfo.buffer.get()->getId() + : 0}); } void OutputLayer::prepareForDeviceLayerRequests() { diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index 523ef7bfbe..bbf42a81aa 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -537,12 +537,13 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate } } -char LayerSnapshot::classifyCompositionForDebug(Composition compositionType) const { +char LayerSnapshot::classifyCompositionForDebug( + const compositionengine::LayerFE::HwcLayerDebugState& hwcState) const { if (!isVisible) { return '.'; } - switch (compositionType) { + switch (hwcState.lastCompositionType) { case Composition::INVALID: return 'i'; case Composition::SOLID_COLOR: @@ -561,21 +562,21 @@ char LayerSnapshot::classifyCompositionForDebug(Composition compositionType) con } char code = '.'; // Default to invisible - if (hasBufferOrSidebandStream()) { - code = 'b'; - } else if (fillsColor()) { - code = 'c'; // Solid color - } else if (hasBlur()) { + if (hasBlur()) { code = 'l'; // Blur } else if (hasProtectedContent) { code = 'p'; // Protected content - } else if (drawShadows()) { - code = 's'; // Shadow } else if (roundedCorner.hasRoundedCorners()) { code = 'r'; // Rounded corners + } else if (drawShadows()) { + code = 's'; // Shadow + } else if (fillsColor()) { + code = 'c'; // Solid color + } else if (hasBufferOrSidebandStream()) { + code = 'b'; } - if (compositionType == Composition::CLIENT) { + if (hwcState.lastCompositionType == Composition::CLIENT) { return static_cast<char>(std::toupper(code)); } else { return code; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 04b9f3b448..69120bdcff 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -24,6 +24,7 @@ #include "RequestedLayerState.h" #include "Scheduler/LayerInfo.h" #include "android-base/stringprintf.h" +#include "compositionengine/LayerFE.h" namespace android::surfaceflinger::frontend { @@ -163,7 +164,7 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { // Returns a char summarizing the composition request // This function tries to maintain parity with planner::Plan chars. char classifyCompositionForDebug( - aidl::android::hardware::graphics::composer3::Composition compositionType) const; + const compositionengine::LayerFE::HwcLayerDebugState& hwcState) const; }; } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index 725a782177..b6192685ae 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -428,13 +428,12 @@ LayerFE::ReleaseFencePromiseStatus LayerFE::getReleaseFencePromiseStatus() { return mReleaseFencePromiseStatus; } -void LayerFE::setHwcCompositionType( - aidl::android::hardware::graphics::composer3::Composition type) { - mLastHwcCompositionType = type; +void LayerFE::setLastHwcState(const LayerFE::HwcLayerDebugState &state) { + mLastHwcState = state; } -aidl::android::hardware::graphics::composer3::Composition LayerFE::getHwcCompositionType() const { - return mLastHwcCompositionType; -} +const LayerFE::HwcLayerDebugState& LayerFE::getLastHwcState() const { + return mLastHwcState; +}; } // namespace android diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h index 64ec27862d..a537456beb 100644 --- a/services/surfaceflinger/LayerFE.h +++ b/services/surfaceflinger/LayerFE.h @@ -59,9 +59,10 @@ public: void setReleaseFence(const FenceResult& releaseFence) override; LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() override; void onPictureProfileCommitted() override; - void setHwcCompositionType(aidl::android::hardware::graphics::composer3::Composition) override; - aidl::android::hardware::graphics::composer3::Composition getHwcCompositionType() - const override; + + // Used for debugging purposes, e.g. perfetto tracing, dumpsys. + void setLastHwcState(const HwcLayerDebugState &state) override; + const HwcLayerDebugState &getLastHwcState() const override; std::unique_ptr<surfaceflinger::frontend::LayerSnapshot> mSnapshot; @@ -93,8 +94,7 @@ private: std::string mName; std::promise<FenceResult> mReleaseFence; ReleaseFencePromiseStatus mReleaseFencePromiseStatus = ReleaseFencePromiseStatus::UNINITIALIZED; - aidl::android::hardware::graphics::composer3::Composition mLastHwcCompositionType = - aidl::android::hardware::graphics::composer3::Composition::INVALID; + HwcLayerDebugState mLastHwcState; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index eecdd72727..f24e441a54 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2980,6 +2980,8 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( int index = 0; ftl::StaticVector<char, WorkloadTracer::COMPOSITION_SUMMARY_SIZE> compositionSummary; auto lastLayerStack = ui::INVALID_LAYER_STACK; + + uint64_t prevOverrideBufferId = 0; for (auto& [layer, layerFE] : layers) { CompositionResult compositionResult{layerFE->stealCompositionResult()}; if (lastLayerStack != layerFE->mSnapshot->outputFilter.layerStack) { @@ -2989,8 +2991,37 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( } lastLayerStack = layerFE->mSnapshot->outputFilter.layerStack; } + + // If there are N layers in a cached set they should all share the same buffer id. + // The first layer in the cached set will be not skipped and layers 1..N-1 will be skipped. + // We expect all layers in the cached set to be marked as composited by HWC. + // Here is a made up example of how it is visualized + // + // [b:rrc][s:cc] + // + // This should be interpreted to mean that there are 2 cached sets. + // So there are only 2 non skipped layers -- b and s. + // The layers rrc and cc are flattened into layers b and s respectively. + const LayerFE::HwcLayerDebugState &hwcState = layerFE->getLastHwcState(); + if (hwcState.overrideBufferId != prevOverrideBufferId) { + // End the existing run. + if (prevOverrideBufferId) { + compositionSummary.push_back(']'); + } + // Start a new run. + if (hwcState.overrideBufferId) { + compositionSummary.push_back('['); + } + } + compositionSummary.push_back( - layerFE->mSnapshot->classifyCompositionForDebug(layerFE->getHwcCompositionType())); + layerFE->mSnapshot->classifyCompositionForDebug(hwcState)); + + if (hwcState.overrideBufferId && !hwcState.wasSkipped) { + compositionSummary.push_back(':'); + } + prevOverrideBufferId = hwcState.overrideBufferId; + if (layerFE->mSnapshot->hasEffect()) { compositedWorkload |= adpf::Workload::EFFECTS; } @@ -3002,6 +3033,10 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( mActivePictureTracker.onLayerComposed(*layer, *layerFE, compositionResult); } } + // End the last run. + if (prevOverrideBufferId) { + compositionSummary.push_back(']'); + } // Concisely describe the layers composited this frame using single chars. GPU composited layers // are uppercase, DPU composited are lowercase. Special chars denote effects (blur, shadow, diff --git a/services/surfaceflinger/common/include/common/WorkloadTracer.h b/services/surfaceflinger/common/include/common/WorkloadTracer.h index 39b6fa1bf4..c4074f72ff 100644 --- a/services/surfaceflinger/common/include/common/WorkloadTracer.h +++ b/services/surfaceflinger/common/include/common/WorkloadTracer.h @@ -23,7 +23,7 @@ namespace android::WorkloadTracer { static constexpr int32_t COMPOSITION_TRACE_COOKIE = 1; static constexpr int32_t POST_COMPOSITION_TRACE_COOKIE = 2; -static constexpr size_t COMPOSITION_SUMMARY_SIZE = 20; +static constexpr size_t COMPOSITION_SUMMARY_SIZE = 64; static constexpr const char* TRACK_NAME = "CriticalWorkload"; } // namespace android::WorkloadTracer
\ No newline at end of file |