Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d9f836d authored by Lloyd Pique's avatar Lloyd Pique
Browse files

[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
parent 4603f3c2
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -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
     */
+25 −0
Original line number Diff line number Diff line
@@ -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: ");
+8 −1
Original line number Diff line number Diff line
@@ -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
+56 −0
Original line number Diff line number Diff line
@@ -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()
 */
+20 −0
Original line number Diff line number Diff line
@@ -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() {
Loading