diff options
| author | 2020-02-11 19:13:09 -0800 | |
|---|---|---|
| committer | 2020-02-13 13:48:35 -0800 | |
| commit | 8d9f836d54548199c397b63e5ab12e7e46d72b19 (patch) | |
| tree | 74ae3fc9fcaaa4fac39a0a131eb1e2a5abb98944 | |
| parent | 4603f3c2151bf6535048b6a42318c8393826b68f (diff) | |
[sf] Pass metadata to layer during composition
Adds the simple bits of code to grab a snapshot of the front-end Layer
generic metadata, storing a copy in LayerFECompositionState, and then
sending int to the HWC2::Layer along with other "geometry update"
settings.
As the metadata stored in the layers uses integer keys, they need to be
translated to name strings. For hard-coded mapping is defined, with a
TODO left to remove the hard-coded mapping.
A test is added to ensure that the metadata is written by OutputLayer
when present, and that it is not set as part of a "per-frame" update.
Bug: 139747351
Test: atest libcompositionengine_test
Change-Id: I63f2a34e1fb70e1aefc5aa7e97ce56b7c2579a29
7 files changed, 158 insertions, 1 deletions
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 40cd3e0c20..d8ce629153 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -40,6 +40,29 @@ namespace android::compositionengine { +// More complex metadata for this layer +struct GenericLayerMetadataEntry { + // True if the metadata may affect the composed result. + // See setLayerGenericMetadata in IComposerClient.hal + bool mandatory; + + // Byte blob or parcel + std::vector<uint8_t> value; + + std::string dumpAsString() const; +}; + +inline bool operator==(const GenericLayerMetadataEntry& lhs, const GenericLayerMetadataEntry& rhs) { + return lhs.mandatory == rhs.mandatory && lhs.value == rhs.value; +} + +// Defining PrintTo helps with Google Tests. +inline void PrintTo(const GenericLayerMetadataEntry& v, ::std::ostream* os) { + *os << v.dumpAsString(); +} + +using GenericLayerMetadataMap = std::unordered_map<std::string, GenericLayerMetadataEntry>; + /* * Used by LayerFE::getCompositionState */ @@ -115,6 +138,8 @@ struct LayerFECompositionState { // The appId for this layer int appId{0}; + GenericLayerMetadataMap metadata; + /* * Per-frame content */ diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp index 3e0f8038d7..02e3a45acd 100644 --- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp @@ -32,6 +32,20 @@ void dumpVal(std::string& out, const char* name, half4 value) { } // namespace +std::string GenericLayerMetadataEntry::dumpAsString() const { + using android::base::StringAppendF; + std::string out; + + out.append("GenericLayerMetadataEntry{mandatory: "); + StringAppendF(&out, "%d", mandatory); + out.append(" value: "); + for (uint8_t byte : value) { + StringAppendF(&out, "0x08%" PRIx8 " ", byte); + } + out.append("]}"); + return out; +} + LayerFECompositionState::~LayerFECompositionState() = default; void LayerFECompositionState::dump(std::string& out) const { @@ -65,6 +79,17 @@ void LayerFECompositionState::dump(std::string& out) const { dumpVal(out, "type", type); dumpVal(out, "appId", appId); + if (!metadata.empty()) { + out.append("\n metadata {"); + for (const auto& [key, entry] : metadata) { + out.append("\n "); + out.append(key); + out.append("="); + out.append(entry.dumpAsString()); + } + out.append("\n }\n "); + } + dumpVal(out, "composition type", toString(compositionType), compositionType); out.append("\n buffer: "); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index b538d7520f..3aa79562cc 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -406,6 +406,14 @@ void OutputLayer::writeOutputIndependentGeometryStateToHWC( ALOGE("[%s] Failed to set info %s (%d)", getLayerFE().getDebugName(), to_string(error).c_str(), static_cast<int32_t>(error)); } + + for (const auto& [name, entry] : outputIndependentState.metadata) { + if (auto error = hwcLayer->setLayerGenericMetadata(name, entry.mandatory, entry.value); + error != HWC2::Error::None) { + ALOGE("[%s] Failed to set generic metadata %s %s (%d)", getLayerFE().getDebugName(), + name.c_str(), to_string(error).c_str(), static_cast<int32_t>(error)); + } + } } void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) { @@ -661,4 +669,3 @@ void OutputLayer::dump(std::string& out) const { } // namespace impl } // namespace android::compositionengine - diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 963062fdbf..1b5617c7eb 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -625,6 +625,8 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static constexpr ui::Dataspace kDataspace = static_cast<ui::Dataspace>(71); static constexpr int kSupportedPerFrameMetadata = 101; static constexpr int kExpectedHwcSlot = 0; + static constexpr bool kLayerGenericMetadata1Mandatory = true; + static constexpr bool kLayerGenericMetadata2Mandatory = true; static const half4 kColor; static const Rect kDisplayFrame; @@ -635,6 +637,10 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static native_handle_t* kSidebandStreamHandle; static const sp<GraphicBuffer> kBuffer; static const sp<Fence> kFence; + static const std::string kLayerGenericMetadata1Key; + static const std::vector<uint8_t> kLayerGenericMetadata1Value; + static const std::string kLayerGenericMetadata2Key; + static const std::vector<uint8_t> kLayerGenericMetadata2Value; OutputLayerWriteStateToHWCTest() { auto& outputLayerState = mOutputLayer.editState(); @@ -669,6 +675,13 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { // Some tests may need to simulate unsupported HWC calls enum class SimulateUnsupported { None, ColorTransform }; + void includeGenericLayerMetadataInState() { + mLayerFEState.metadata[kLayerGenericMetadata1Key] = {kLayerGenericMetadata1Mandatory, + kLayerGenericMetadata1Value}; + mLayerFEState.metadata[kLayerGenericMetadata2Key] = {kLayerGenericMetadata2Mandatory, + kLayerGenericMetadata2Value}; + } + void expectGeometryCommonCalls() { EXPECT_CALL(*mHwcLayer, setDisplayFrame(kDisplayFrame)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setSourceCrop(kSourceCrop)).WillOnce(Return(kError)); @@ -720,6 +733,18 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, kBuffer, kFence)); } + void expectGenericLayerMetadataCalls() { + // Note: Can be in any order. + EXPECT_CALL(*mHwcLayer, + setLayerGenericMetadata(kLayerGenericMetadata1Key, + kLayerGenericMetadata1Mandatory, + kLayerGenericMetadata1Value)); + EXPECT_CALL(*mHwcLayer, + setLayerGenericMetadata(kLayerGenericMetadata2Key, + kLayerGenericMetadata2Mandatory, + kLayerGenericMetadata2Value)); + } + std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()}; StrictMock<mock::DisplayColorProfile> mDisplayColorProfile; }; @@ -739,6 +764,13 @@ native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle = reinterpret_cast<native_handle_t*>(1031); const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer; const sp<Fence> OutputLayerWriteStateToHWCTest::kFence; +const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key = + "com.example.metadata.1"; +const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Value{{1, 2, 3}}; +const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata2Key = + "com.example.metadata.2"; +const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata2Value{ + {4, 5, 6, 7}}; TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoFECompositionState) { EXPECT_CALL(*mLayerFE, getCompositionState()).WillOnce(Return(nullptr)); @@ -862,6 +894,30 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompo mOutputLayer.writeStateToHWC(false); } +TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) { + mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + includeGenericLayerMetadataInState(); + + expectGeometryCommonCalls(); + expectPerFrameCommonCalls(); + expectSetHdrMetadataAndBufferCalls(); + expectGenericLayerMetadataCalls(); + expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + + mOutputLayer.writeStateToHWC(true); +} + +TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPresent) { + mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + includeGenericLayerMetadataInState(); + + expectPerFrameCommonCalls(); + expectSetHdrMetadataAndBufferCalls(); + expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + + mOutputLayer.writeStateToHWC(false); +} + /* * OutputLayer::writeCursorPositionToHWC() */ diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 6ff23c5f51..e04e0ab996 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -475,6 +475,26 @@ void Layer::prepareGeometryCompositionState() { compositionState->type = type; compositionState->appId = appId; + + compositionState->metadata.clear(); + const auto& supportedMetadata = mFlinger->getHwComposer().getSupportedLayerGenericMetadata(); + for (const auto& [key, mandatory] : supportedMetadata) { + const auto& genericLayerMetadataCompatibilityMap = + mFlinger->getGenericLayerMetadataKeyMap(); + auto compatIter = genericLayerMetadataCompatibilityMap.find(key); + if (compatIter == std::end(genericLayerMetadataCompatibilityMap)) { + continue; + } + const uint32_t id = compatIter->second; + + auto it = drawingState.metadata.mMap.find(id); + if (it == std::end(drawingState.metadata.mMap)) { + continue; + } + + compositionState->metadata + .emplace(key, compositionengine::GenericLayerMetadataEntry{mandatory, it->second}); + } } void Layer::preparePerFrameCompositionState() { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7ed6342dd9..084251c93e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5851,6 +5851,21 @@ status_t SurfaceFlinger::setGlobalShadowSettings(const half4& ambientColor, cons return NO_ERROR; } +const std::unordered_map<std::string, uint32_t>& SurfaceFlinger::getGenericLayerMetadataKeyMap() + const { + // TODO(b/149500060): Remove this fixed/static mapping. Please prefer taking + // on the work to remove the table in that bug rather than adding more to + // it. + static const std::unordered_map<std::string, uint32_t> genericLayerMetadataKeyMap{ + // Note: METADATA_OWNER_UID and METADATA_WINDOW_TYPE are officially + // supported, and exposed via the + // IVrComposerClient::VrCommand::SET_LAYER_INFO command. + {"org.chromium.arc.V1_0.TaskId", METADATA_TASK_ID}, + {"org.chromium.arc.V1_0.CursorInfo", METADATA_MOUSE_CURSOR}, + }; + return genericLayerMetadataKeyMap; +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8cabcf0ef6..763df2353d 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1153,6 +1153,15 @@ private: std::atomic<nsecs_t> mExpectedPresentTime = 0; + /* ------------------------------------------------------------------------ + * Generic Layer Metadata + */ + const std::unordered_map<std::string, uint32_t>& getGenericLayerMetadataKeyMap() const; + + /* ------------------------------------------------------------------------ + * Misc + */ + std::mutex mActiveConfigLock; // This bit is set once we start setting the config. We read from this bit during the // process. If at the end, this bit is different than mDesiredActiveConfig, we restart |