summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h')
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h478
1 files changed, 478 insertions, 0 deletions
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
new file mode 100644
index 0000000000..bce438fa13
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -0,0 +1,478 @@
+/*
+ * Copyright 2021 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
+
+#include <android-base/strings.h>
+#include <compositionengine/LayerFE.h>
+#include <compositionengine/LayerFECompositionState.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <input/Flags.h>
+
+#include <string>
+
+#include "DisplayHardware/Hal.h"
+#include "math/HashCombine.h"
+
+namespace std {
+template <typename T>
+struct hash<android::sp<T>> {
+ size_t operator()(const android::sp<T>& p) { return std::hash<void*>()(p.get()); }
+};
+
+template <typename T>
+struct hash<android::wp<T>> {
+ size_t operator()(const android::wp<T>& p) {
+ android::sp<T> promoted = p.promote();
+ return std::hash<void*>()(promoted ? promoted.get() : nullptr);
+ }
+};
+} // namespace std
+
+namespace android::compositionengine::impl::planner {
+
+using LayerId = int32_t;
+
+// clang-format off
+enum class LayerStateField : uint32_t {
+ None = 0u,
+ Id = 1u << 0,
+ Name = 1u << 1,
+ DisplayFrame = 1u << 2,
+ SourceCrop = 1u << 3,
+ BufferTransform = 1u << 4,
+ BlendMode = 1u << 5,
+ Alpha = 1u << 6,
+ LayerMetadata = 1u << 7,
+ VisibleRegion = 1u << 8,
+ Dataspace = 1u << 9,
+ PixelFormat = 1u << 10,
+ ColorTransform = 1u << 11,
+ SurfaceDamage = 1u << 12,
+ CompositionType = 1u << 13,
+ SidebandStream = 1u << 14,
+ Buffer = 1u << 15,
+ SolidColor = 1u << 16,
+ BackgroundBlurRadius = 1u << 17,
+ BlurRegions = 1u << 18,
+};
+// clang-format on
+
+std::string to_string(LayerStateField field);
+
+// An abstract interface allows us to iterate over all of the OutputLayerState fields
+// without having to worry about their templated types.
+// See `LayerState::getNonUniqueFields` below.
+class StateInterface {
+public:
+ virtual ~StateInterface() = default;
+
+ virtual Flags<LayerStateField> update(const compositionengine::OutputLayer* layer) = 0;
+
+ virtual size_t getHash() const = 0;
+
+ virtual LayerStateField getField() const = 0;
+
+ virtual Flags<LayerStateField> getFieldIfDifferent(const StateInterface* other) const = 0;
+
+ virtual bool equals(const StateInterface* other) const = 0;
+
+ virtual std::vector<std::string> toStrings() const = 0;
+};
+
+template <typename T, LayerStateField FIELD>
+class OutputLayerState : public StateInterface {
+public:
+ using ReadFromLayerState = std::function<T(const compositionengine::OutputLayer* layer)>;
+ using ToStrings = std::function<std::vector<std::string>(const T&)>;
+ using Equals = std::function<bool(const T&, const T&)>;
+ using Hashes = std::function<size_t(const T&)>;
+
+ static ToStrings getDefaultToStrings() {
+ return [](const T& value) {
+ using std::to_string;
+ return std::vector<std::string>{to_string(value)};
+ };
+ }
+
+ static ToStrings getHalToStrings() {
+ return [](const T& value) { return std::vector<std::string>{toString(value)}; };
+ }
+
+ static ToStrings getRegionToStrings() {
+ return [](const Region& region) {
+ using namespace std::string_literals;
+ std::string dump;
+ region.dump(dump, "");
+ std::vector<std::string> split = base::Split(dump, "\n"s);
+ split.erase(split.begin()); // Strip the header
+ split.pop_back(); // Strip the last (empty) line
+ for (std::string& line : split) {
+ line.erase(0, 4); // Strip leading padding before each rect
+ }
+ return split;
+ };
+ }
+
+ static Equals getDefaultEquals() {
+ return [](const T& lhs, const T& rhs) { return lhs == rhs; };
+ }
+
+ static Equals getRegionEquals() {
+ return [](const Region& lhs, const Region& rhs) { return lhs.hasSameRects(rhs); };
+ }
+
+ static Hashes getDefaultHashes() {
+ return [](const T& value) { return std::hash<T>{}(value); };
+ }
+
+ OutputLayerState(ReadFromLayerState reader,
+ ToStrings toStrings = OutputLayerState::getDefaultToStrings(),
+ Equals equals = OutputLayerState::getDefaultEquals(),
+ Hashes hashes = OutputLayerState::getDefaultHashes())
+ : mReader(reader), mToStrings(toStrings), mEquals(equals), mHashes(hashes) {}
+
+ ~OutputLayerState() override = default;
+
+ // Returns this member's field flag if it was changed
+ Flags<LayerStateField> update(const compositionengine::OutputLayer* layer) override {
+ T newValue = mReader(layer);
+ return update(newValue);
+ }
+
+ Flags<LayerStateField> update(const T& newValue) {
+ if (!mEquals(mValue, newValue)) {
+ mValue = newValue;
+ mHash = {};
+ return FIELD;
+ }
+ return {};
+ }
+
+ LayerStateField getField() const override { return FIELD; }
+ const T& get() const { return mValue; }
+
+ size_t getHash() const override {
+ if (!mHash) {
+ mHash = mHashes(mValue);
+ }
+ return *mHash;
+ }
+
+ Flags<LayerStateField> getFieldIfDifferent(const StateInterface* other) const override {
+ if (other->getField() != FIELD) {
+ return {};
+ }
+
+ // The early return ensures that this downcast is sound
+ const OutputLayerState* otherState = static_cast<const OutputLayerState*>(other);
+ return *this != *otherState ? FIELD : Flags<LayerStateField>{};
+ }
+
+ bool equals(const StateInterface* other) const override {
+ if (other->getField() != FIELD) {
+ return false;
+ }
+
+ // The early return ensures that this downcast is sound
+ const OutputLayerState* otherState = static_cast<const OutputLayerState*>(other);
+ return *this == *otherState;
+ }
+
+ std::vector<std::string> toStrings() const override { return mToStrings(mValue); }
+
+ bool operator==(const OutputLayerState& other) const { return mEquals(mValue, other.mValue); }
+ bool operator!=(const OutputLayerState& other) const { return !(*this == other); }
+
+private:
+ const ReadFromLayerState mReader;
+ const ToStrings mToStrings;
+ const Equals mEquals;
+ const Hashes mHashes;
+ T mValue = {};
+ mutable std::optional<size_t> mHash = {};
+};
+
+class LayerState {
+public:
+ LayerState(compositionengine::OutputLayer* layer);
+
+ // Returns which fields were updated
+ Flags<LayerStateField> update(compositionengine::OutputLayer*);
+
+ // Computes a hash for this LayerState.
+ // The hash is only computed from NonUniqueFields, and excludes GraphicBuffers since they are
+ // not guaranteed to live longer than the LayerState object.
+ size_t getHash() const;
+
+ // Returns the bit-set of differing fields between this LayerState and another LayerState.
+ // This bit-set is based on NonUniqueFields only, and excludes GraphicBuffers.
+ Flags<LayerStateField> getDifferingFields(const LayerState& other) const;
+
+ compositionengine::OutputLayer* getOutputLayer() const { return mOutputLayer; }
+ int32_t getId() const { return mId.get(); }
+ const std::string& getName() const { return mName.get(); }
+ Rect getDisplayFrame() const { return mDisplayFrame.get(); }
+ const Region& getVisibleRegion() const { return mVisibleRegion.get(); }
+ bool hasBlurBehind() const {
+ return mBackgroundBlurRadius.get() > 0 || !mBlurRegions.get().empty();
+ }
+ int32_t getBackgroundBlurRadius() const { return mBackgroundBlurRadius.get(); }
+ hardware::graphics::composer::hal::Composition getCompositionType() const {
+ return mCompositionType.get();
+ }
+
+ void incrementFramesSinceBufferUpdate() { ++mFramesSinceBufferUpdate; }
+ void resetFramesSinceBufferUpdate() { mFramesSinceBufferUpdate = 0; }
+ int64_t getFramesSinceBufferUpdate() const { return mFramesSinceBufferUpdate; }
+
+ ui::Dataspace getDataspace() const { return mOutputDataspace.get(); }
+
+ bool isProtected() const {
+ return getOutputLayer()->getLayerFE().getCompositionState()->hasProtectedContent;
+ }
+
+ void dump(std::string& result) const;
+ std::optional<std::string> compare(const LayerState& other) const;
+
+ // This makes LayerState's private members accessible to the operator
+ friend bool operator==(const LayerState& lhs, const LayerState& rhs);
+ friend bool operator!=(const LayerState& lhs, const LayerState& rhs) { return !(lhs == rhs); }
+
+private:
+ compositionengine::OutputLayer* mOutputLayer = nullptr;
+
+ OutputLayerState<LayerId, LayerStateField::Id> mId{
+ [](const compositionengine::OutputLayer* layer) {
+ return layer->getLayerFE().getSequence();
+ }};
+
+ OutputLayerState<std::string, LayerStateField::Name>
+ mName{[](auto layer) { return layer->getLayerFE().getDebugName(); },
+ [](const std::string& name) { return std::vector<std::string>{name}; }};
+
+ // Output-dependent geometry state
+
+ OutputLayerState<Rect, LayerStateField::DisplayFrame>
+ mDisplayFrame{[](auto layer) { return layer->getState().displayFrame; },
+ [](const Rect& rect) {
+ return std::vector<std::string>{
+ base::StringPrintf("[%d, %d, %d, %d]", rect.left, rect.top,
+ rect.right, rect.bottom)};
+ }};
+
+ OutputLayerState<FloatRect, LayerStateField::SourceCrop>
+ mSourceCrop{[](auto layer) { return layer->getState().sourceCrop; },
+ [](const FloatRect& rect) {
+ return std::vector<std::string>{
+ base::StringPrintf("[%.2f, %.2f, %.2f, %.2f]", rect.left,
+ rect.top, rect.right, rect.bottom)};
+ }};
+
+ using BufferTransformState = OutputLayerState<hardware::graphics::composer::hal::Transform,
+ LayerStateField::BufferTransform>;
+ BufferTransformState mBufferTransform{[](auto layer) {
+ return layer->getState().bufferTransform;
+ },
+ BufferTransformState::getHalToStrings()};
+
+ // Output-independent geometry state
+
+ using BlendModeState = OutputLayerState<hardware::graphics::composer::hal::BlendMode,
+ LayerStateField::BlendMode>;
+ BlendModeState mBlendMode{[](auto layer) {
+ return layer->getLayerFE().getCompositionState()->blendMode;
+ },
+ BlendModeState::getHalToStrings()};
+
+ OutputLayerState<float, LayerStateField::Alpha> mAlpha{
+ [](auto layer) { return layer->getLayerFE().getCompositionState()->alpha; }};
+
+ using LayerMetadataState =
+ OutputLayerState<GenericLayerMetadataMap, LayerStateField::LayerMetadata>;
+ LayerMetadataState
+ mLayerMetadata{[](auto layer) {
+ return layer->getLayerFE().getCompositionState()->metadata;
+ },
+ [](const GenericLayerMetadataMap& metadata) {
+ std::vector<std::string> result;
+ if (metadata.empty()) {
+ result.push_back("{}");
+ return result;
+ }
+ result.push_back("{");
+ for (const auto& [key, value] : metadata) {
+ std::string keyValueDump;
+ keyValueDump.append(" ");
+ keyValueDump.append(key);
+ keyValueDump.append("=");
+ keyValueDump.append(value.dumpAsString());
+ result.push_back(keyValueDump);
+ }
+ result.push_back("}");
+ return result;
+ },
+ LayerMetadataState::getDefaultEquals(),
+ [](const GenericLayerMetadataMap& metadata) {
+ size_t hash = 0;
+ for (const auto& [key, value] : metadata) {
+ size_t entryHash = 0;
+ hashCombineSingleHashed(entryHash,
+ std::hash<std::string>{}(key));
+ hashCombineSingleHashed(entryHash,
+ GenericLayerMetadataEntry::Hasher{}(
+ value));
+ hash ^= entryHash;
+ }
+ return hash;
+ }};
+
+ // Output-dependent per-frame state
+
+ using VisibleRegionState = OutputLayerState<Region, LayerStateField::VisibleRegion>;
+ VisibleRegionState mVisibleRegion{[](auto layer) { return layer->getState().visibleRegion; },
+ VisibleRegionState::getRegionToStrings(),
+ VisibleRegionState::getRegionEquals()};
+
+ using DataspaceState = OutputLayerState<ui::Dataspace, LayerStateField::Dataspace>;
+ DataspaceState mOutputDataspace{[](auto layer) { return layer->getState().dataspace; },
+ DataspaceState::getHalToStrings()};
+
+ // Output-independent per-frame state
+
+ using PixelFormatState = OutputLayerState<hardware::graphics::composer::hal::PixelFormat,
+ LayerStateField::PixelFormat>;
+ PixelFormatState
+ mPixelFormat{[](auto layer) {
+ return layer->getLayerFE().getCompositionState()->buffer
+ ? static_cast<hardware::graphics::composer::hal::PixelFormat>(
+ layer->getLayerFE()
+ .getCompositionState()
+ ->buffer->getPixelFormat())
+ : hardware::graphics::composer::hal::PixelFormat::RGBA_8888;
+ },
+ PixelFormatState::getHalToStrings()};
+
+ OutputLayerState<mat4, LayerStateField::ColorTransform> mColorTransform;
+
+ using CompositionTypeState = OutputLayerState<hardware::graphics::composer::hal::Composition,
+ LayerStateField::CompositionType>;
+ CompositionTypeState
+ mCompositionType{[](auto layer) {
+ return layer->getState().forceClientComposition
+ ? hardware::graphics::composer::hal::Composition::CLIENT
+ : layer->getLayerFE()
+ .getCompositionState()
+ ->compositionType;
+ },
+ CompositionTypeState::getHalToStrings()};
+
+ OutputLayerState<void*, LayerStateField::SidebandStream>
+ mSidebandStream{[](auto layer) {
+ return layer->getLayerFE()
+ .getCompositionState()
+ ->sidebandStream.get();
+ },
+ [](void* p) {
+ return std::vector<std::string>{base::StringPrintf("%p", p)};
+ }};
+
+ OutputLayerState<wp<GraphicBuffer>, LayerStateField::Buffer>
+ mBuffer{[](auto layer) { return layer->getLayerFE().getCompositionState()->buffer; },
+ [](const wp<GraphicBuffer>& buffer) {
+ sp<GraphicBuffer> promotedBuffer = buffer.promote();
+ return std::vector<std::string>{
+ base::StringPrintf("%p",
+ promotedBuffer ? promotedBuffer.get()
+ : nullptr)};
+ }};
+
+ int64_t mFramesSinceBufferUpdate = 0;
+
+ OutputLayerState<half4, LayerStateField::SolidColor>
+ mSolidColor{[](auto layer) { return layer->getLayerFE().getCompositionState()->color; },
+ [](const half4& vec) {
+ std::stringstream stream;
+ stream << vec;
+ return std::vector<std::string>{stream.str()};
+ }};
+
+ OutputLayerState<int32_t, LayerStateField::BackgroundBlurRadius> mBackgroundBlurRadius{
+ [](auto layer) {
+ return layer->getLayerFE().getCompositionState()->backgroundBlurRadius;
+ }};
+
+ using BlurRegionsState =
+ OutputLayerState<std::vector<BlurRegion>, LayerStateField::BlurRegions>;
+ BlurRegionsState mBlurRegions{[](auto layer) {
+ return layer->getLayerFE().getCompositionState()->blurRegions;
+ },
+ [](const std::vector<BlurRegion>& regions) {
+ std::vector<std::string> result;
+ for (const auto region : regions) {
+ std::string str;
+ base::StringAppendF(&str,
+ "{radius=%du, cornerRadii=[%f, %f, "
+ "%f, %f], alpha=%f, rect=[%d, "
+ "%d, %d, %d]",
+ region.blurRadius,
+ region.cornerRadiusTL,
+ region.cornerRadiusTR,
+ region.cornerRadiusBL,
+ region.cornerRadiusBR, region.alpha,
+ region.left, region.top, region.right,
+ region.bottom);
+ result.push_back(str);
+ }
+ return result;
+ },
+ BlurRegionsState::getDefaultEquals(),
+ [](const std::vector<BlurRegion>& regions) {
+ size_t hash = 0;
+ for (const auto& region : regions) {
+ android::hashCombineSingle(hash, region);
+ }
+ return hash;
+ }};
+
+ static const constexpr size_t kNumNonUniqueFields = 16;
+
+ std::array<StateInterface*, kNumNonUniqueFields> getNonUniqueFields() {
+ std::array<const StateInterface*, kNumNonUniqueFields> constFields =
+ const_cast<const LayerState*>(this)->getNonUniqueFields();
+ std::array<StateInterface*, kNumNonUniqueFields> fields;
+ std::transform(constFields.cbegin(), constFields.cend(), fields.begin(),
+ [](const StateInterface* constField) {
+ return const_cast<StateInterface*>(constField);
+ });
+ return fields;
+ }
+
+ std::array<const StateInterface*, kNumNonUniqueFields> getNonUniqueFields() const {
+ return {
+ &mDisplayFrame, &mSourceCrop, &mBufferTransform, &mBlendMode,
+ &mAlpha, &mLayerMetadata, &mVisibleRegion, &mOutputDataspace,
+ &mPixelFormat, &mColorTransform, &mCompositionType, &mSidebandStream,
+ &mBuffer, &mSolidColor, &mBackgroundBlurRadius, &mBlurRegions,
+ };
+ }
+};
+
+using NonBufferHash = size_t;
+NonBufferHash getNonBufferHash(const std::vector<const LayerState*>&);
+
+} // namespace android::compositionengine::impl::planner