/* * 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 #include #include #include #include #include #include #include "DisplayHardware/Hal.h" #include "math/HashCombine.h" namespace std { template struct hash> { size_t operator()(const android::sp& p) { return std::hash()(p.get()); } }; template struct hash> { size_t operator()(const android::wp& p) { android::sp promoted = p.promote(); return std::hash()(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 update(const compositionengine::OutputLayer* layer) = 0; virtual size_t getHash() const = 0; virtual LayerStateField getField() const = 0; virtual Flags getFieldIfDifferent(const StateInterface* other) const = 0; virtual bool equals(const StateInterface* other) const = 0; virtual std::vector toStrings() const = 0; }; template class OutputLayerState : public StateInterface { public: using ReadFromLayerState = std::function; using ToStrings = std::function(const T&)>; using Equals = std::function; using Hashes = std::function; static ToStrings getDefaultToStrings() { return [](const T& value) { using std::to_string; return std::vector{to_string(value)}; }; } static ToStrings getHalToStrings() { return [](const T& value) { return std::vector{toString(value)}; }; } static ToStrings getRegionToStrings() { return [](const Region& region) { using namespace std::string_literals; std::string dump; region.dump(dump, ""); std::vector 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{}(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 update(const compositionengine::OutputLayer* layer) override { T newValue = mReader(layer); return update(newValue); } Flags 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 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(other); return *this != *otherState ? FIELD : Flags{}; } 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(other); return *this == *otherState; } std::vector 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 mHash = {}; }; class LayerState { public: LayerState(compositionengine::OutputLayer* layer); // Returns which fields were updated Flags 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 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 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 mId{ [](const compositionengine::OutputLayer* layer) { return layer->getLayerFE().getSequence(); }}; OutputLayerState mName{[](auto layer) { return layer->getLayerFE().getDebugName(); }, [](const std::string& name) { return std::vector{name}; }}; // Output-dependent geometry state OutputLayerState mDisplayFrame{[](auto layer) { return layer->getState().displayFrame; }, [](const Rect& rect) { return std::vector{ base::StringPrintf("[%d, %d, %d, %d]", rect.left, rect.top, rect.right, rect.bottom)}; }}; OutputLayerState mSourceCrop{[](auto layer) { return layer->getState().sourceCrop; }, [](const FloatRect& rect) { return std::vector{ base::StringPrintf("[%.2f, %.2f, %.2f, %.2f]", rect.left, rect.top, rect.right, rect.bottom)}; }}; using BufferTransformState = OutputLayerState; BufferTransformState mBufferTransform{[](auto layer) { return layer->getState().bufferTransform; }, BufferTransformState::getHalToStrings()}; // Output-independent geometry state using BlendModeState = OutputLayerState; BlendModeState mBlendMode{[](auto layer) { return layer->getLayerFE().getCompositionState()->blendMode; }, BlendModeState::getHalToStrings()}; OutputLayerState mAlpha{ [](auto layer) { return layer->getLayerFE().getCompositionState()->alpha; }}; using LayerMetadataState = OutputLayerState; LayerMetadataState mLayerMetadata{[](auto layer) { return layer->getLayerFE().getCompositionState()->metadata; }, [](const GenericLayerMetadataMap& metadata) { std::vector 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{}(key)); hashCombineSingleHashed(entryHash, GenericLayerMetadataEntry::Hasher{}( value)); hash ^= entryHash; } return hash; }}; // Output-dependent per-frame state using VisibleRegionState = OutputLayerState; VisibleRegionState mVisibleRegion{[](auto layer) { return layer->getState().visibleRegion; }, VisibleRegionState::getRegionToStrings(), VisibleRegionState::getRegionEquals()}; using DataspaceState = OutputLayerState; DataspaceState mOutputDataspace{[](auto layer) { return layer->getState().dataspace; }, DataspaceState::getHalToStrings()}; // Output-independent per-frame state using PixelFormatState = OutputLayerState; PixelFormatState mPixelFormat{[](auto layer) { return layer->getLayerFE().getCompositionState()->buffer ? static_cast( layer->getLayerFE() .getCompositionState() ->buffer->getPixelFormat()) : hardware::graphics::composer::hal::PixelFormat::RGBA_8888; }, PixelFormatState::getHalToStrings()}; OutputLayerState mColorTransform; using CompositionTypeState = OutputLayerState; CompositionTypeState mCompositionType{[](auto layer) { return layer->getState().forceClientComposition ? hardware::graphics::composer::hal::Composition::CLIENT : layer->getLayerFE() .getCompositionState() ->compositionType; }, CompositionTypeState::getHalToStrings()}; OutputLayerState mSidebandStream{[](auto layer) { return layer->getLayerFE() .getCompositionState() ->sidebandStream.get(); }, [](void* p) { return std::vector{base::StringPrintf("%p", p)}; }}; OutputLayerState, LayerStateField::Buffer> mBuffer{[](auto layer) { return layer->getLayerFE().getCompositionState()->buffer; }, [](const wp& buffer) { sp promotedBuffer = buffer.promote(); return std::vector{ base::StringPrintf("%p", promotedBuffer ? promotedBuffer.get() : nullptr)}; }}; int64_t mFramesSinceBufferUpdate = 0; OutputLayerState mSolidColor{[](auto layer) { return layer->getLayerFE().getCompositionState()->color; }, [](const half4& vec) { std::stringstream stream; stream << vec; return std::vector{stream.str()}; }}; OutputLayerState mBackgroundBlurRadius{ [](auto layer) { return layer->getLayerFE().getCompositionState()->backgroundBlurRadius; }}; using BlurRegionsState = OutputLayerState, LayerStateField::BlurRegions>; BlurRegionsState mBlurRegions{[](auto layer) { return layer->getLayerFE().getCompositionState()->blurRegions; }, [](const std::vector& regions) { std::vector 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& 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 getNonUniqueFields() { std::array constFields = const_cast(this)->getNonUniqueFields(); std::array fields; std::transform(constFields.cbegin(), constFields.cend(), fields.begin(), [](const StateInterface* constField) { return const_cast(constField); }); return fields; } std::array 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&); } // namespace android::compositionengine::impl::planner