diff options
Diffstat (limited to 'services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h')
-rw-r--r-- | services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h | 478 |
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 |